home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / xlib50.zip / XLIB.DOC < prev   
Text File  |  1995-02-15  |  180KB  |  4,281 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.                              XLIB PROGRAMMER'S MANUAL
  32.                                    VERSION 5.0
  33.  
  34.                               (DOS Extender Library)
  35.  
  36.                                 TechniLib Company
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.                   Copyright 1993-1995, by TechniLib (TM) Company
  61.                                All Rights Reserved
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.                           TERMS OF USE AND DISTRIBUTION
  69.  
  70.  
  71.        XLIB is a shareware product; therefore, unregistered copies of XLIB are
  72.   made available free of charge so that potential purchasers will have the
  73.   opportunity to examine and test the software before committing payment.
  74.   Distribution of unregistered copies of XLIB to other potential users is also
  75.   permitted and appreciated.  However, usage and distribution of XLIB must
  76.   conform to the following conditions.  In the following statement, the term
  77.   "commercial distribution," includes shareware distribution.
  78.  
  79.   1) XLIB and accompanying software must be distributed together in copies of
  80.   the original archive provided by TechniLib.  Neither the archive nor
  81.   individual files therein may be modified.
  82.  
  83.   2) The XLIB archive may be distributed in combination with other shareware
  84.   products; however, the XLIB archive may not be distributed with other
  85.   commercially distributed software without written consent of TechniLib.
  86.  
  87.   3) Copies of XLIB which have been used to develop software for commercial
  88.   distribution must be registered before such software is marketed.  Copies of
  89.   XLIB which have been used to develop noncommercial software must be registered
  90.   if such software is to be regularly used either by the developer or others.
  91.  
  92.   4) Commercially distributed software must embed XLIB procedures in the
  93.   software code.  Files contained in the XLIB archive may not be placed in the
  94.   distribution media.
  95.  
  96.   5) XLIB is designed to offer a set of services to other executable code.  XLIB
  97.   may not be used to develop software for commercial distribution which will
  98.   essentially offer any of these same services to other executable code.
  99.   Exceptions to this condition require written consent of TechniLib.
  100.  
  101.   6) Rights afforded by registering a single copy of XLIB pertain only to a
  102.   single computer.
  103.  
  104.   7) XLIB may be registered for a fee of $50.00 per copy.  Accompany payment
  105.   with return address.  Registrants will be entitled to the most recent version
  106.   of the XLIB archive.
  107.  
  108.  
  109.                               DISCLAIMER OF WARRANTY
  110.  
  111.  
  112.        XLIB AND ALL ACCOMPANYING SOFTWARE AND LITERATURE ARE DISTRIBUTED WITH
  113.   THE EXCLUSION OF ANY AND ALL IMPLIED WARRANTIES, AND WITH THE EXCLUSION OF
  114.   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  TechniLib
  115.   SHALL HAVE NO LIABILITY FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  116.   RESULTING FROM THE USE OF XLIB OR ACCOMPANYING MATERIALS.  The user assumes
  117.   the entire risk of using this software.
  118.  
  119.  
  120.                   Copyright 1993-1995, by TechniLib (TM) Company
  121.                                All Rights Reserved
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.                                 TABLE OF CONTENTS
  129.  
  130.  
  131.   CHAPTERS
  132.                                                                       Page
  133.   1.  Introduction                                                       1
  134.   2.  XLIB Conventions and Structure                                     5
  135.   3.  XLIB Initialization and Termination                                8
  136.   4.  Mode Switching                                                    11
  137.   5.  Inline Mode Switching                                             15
  138.   6.  Interrupt Management                                              19
  139.   7.  Memory Management                                                 26
  140.   8.  File Management                                                   31
  141.   9.  Descriptor Management                                             36
  142.   10. Using XLIB in High-Level Language Libraries                       37
  143.   11. Using XLIBE for Debugging and Exception Trapping                  41
  144.  
  145.  
  146.   TABLES
  147.                                                                       Page
  148.   1.  XLIB Segments and Selectors by Public Symbol                       6
  149.   2.  IFLAGS Settings for Memory Allocation Control                      9
  150.   3.  CALLPM/ENTERPM Register Storage Locations by Public Symbol        13
  151.   4.  CALLRM Register Storage Locations by Public Symbol                14
  152.   5.  XLIB File Control Block Structure                                 31
  153.  
  154.  
  155.   EXAMPLES
  156.                                                                       Page
  157.   1.  Simple Mode Switching Under XLIB                                   3
  158.   2.  Using INLINEPM/INLINERM in C                                      16
  159.   3.  Calling Protected-Mode Libraries From BASIC                       37
  160.  
  161.  
  162.   APPENDICES
  163.                                                                       Page
  164.   A. Description of XLIB Public Data                                    45
  165.   B. XLIB Error Codes                                                   49
  166.   C. DPMI 1.0 Error Codes                                               51
  167.   D. XMS Error Codes                                                    52
  168.   E. Calling Protected-Mode Libraries From C                            53
  169.   F. Technical Support                                                  55
  170.   G. The SWITCHPM and SWITCHRM Procedures                               56
  171.   H. Debugging                                                          57
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.                                        iii
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.                         INDEX TO PROCEDURE SPECIFICATIONS
  193.  
  194.  
  195.   Initialization Routines
  196.  
  197.   Name          Purpose                                          CPU Mode   Page
  198.   INITXLIB      Initialize XLIB                                  Real          9
  199.   XLIBMEMREQ    Get XLIB convention memory requirements          Real         10
  200.   DPMIMEMREQ    Get DPMI conventional memory requirements        Real         10
  201.   VCPIMEMREQ    Get VCPI conventional memory requirements        Real         10
  202.   XLIBCONFIG    Get XLIB post-initialization configuration       Real         10
  203.  
  204.   Mode Switch Routines
  205.  
  206.   Name          Purpose                                          CPU Mode   Page
  207.   CALLPM        Call protected-mode procedure                    Real         12
  208.   RETPM         Return from protected mode to real mode          Protected    12
  209.   ENTERPM       Call protected mode procedure                    Real         12
  210.   EXITPM        Return from protected mode to real mode          Protected    13
  211.   CALLRM        Call real-mode procedure from protected mode     Protected    13
  212.  
  213.   Inline Mode Switch Routines
  214.  
  215.   Name          Purpose                                          CPU Mode   Page
  216.   INLINEPM      Return to caller in protected mode               Real         17
  217.   INLINERM      Return to caller in real mode                    Protected    18
  218.   CALL32        Call 32-bit procedure from 16-bit protected mode Protected    18
  219.  
  220.   Interrupt Management Routines
  221.  
  222.   Name          Purpose                                          CPU Mode   Page
  223.   PMGETRMIV     Get real-mode interrupt vector                   Protected    23
  224.   PMSETRMIV     Set real-mode interrupt vector                   Protected    23
  225.   GETPMIV       Get protected-mode interrupt vector              Real         24
  226.   SETPMIV       Set protected-mode interrupt vector              Real         24
  227.   PMGETPMIV     Get protected-mode interrupt vector              Protected    24
  228.   PMSETPMIV     Set protected mode interrupt vector              Protected    25
  229.   DEFLECTPM     Deflect real-mode interrupt to protected mode    Real         25
  230.   SWITCHPM      Perform nestable switch to protected mode        Real         56
  231.   SWITCHRM      Perform nestable switch to real mode             Real         56
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.                                         iv
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.                   INDEX TO PROCEDURE SPECIFICATIONS (CONTINUED)
  257.  
  258.  
  259.   Memory Management Routines
  260.  
  261.   Name          Purpose                                          CPU Mode   Page
  262.   PMGETDOSMEM   Allocate DOS memory block                        Protected    27
  263.   PMFREEDOSMEM  Release DOS memory block                         Protected    27
  264.   GETMEM        Allocate extended memory block                   Real         27
  265.   FREEMEM       Release extended memory block                    Real         28
  266.   RESETMEM      Release all extended memory blocks               Real         28
  267.   PMGETMEM      Allocate extended memory block                   Protected    28
  268.   PMFREEMEM     Release extended memory block                    Protected    29
  269.   PMRESETMEM    Release all extended memory blocks               Protected    29
  270.   MAPIO         Get logical address for memory-mapped IO device  Real         29
  271.   PMMAPIO       Get logical address for memory-mapped IO device  Protected    29
  272.   GETUMEM       Allocate uncommitted memory block                Real         30
  273.   UNCOMMITMEM   Uncommit memory in logical address space         Real         30
  274.   PMGETUMEM     Allocate uncommitted memory block                Protected    30
  275.   PMUNCOMMITMEM Uncommit memory in logical address space         Protected    30
  276.  
  277.   File Management Routines
  278.  
  279.   Name          Purpose                                          CPU Mode   Page
  280.   XCREATE       Create file                                      Real         32
  281.   XOPEN         Open existing file                               Real         32
  282.   XCLOSE        Close file                                       Real         33
  283.   XSAVE         Save memory to created file                      Real         33
  284.   XLOAD         Load entire file to memory                       Real         33
  285.   XWRITE        Random write from memory to file                 Real         34
  286.   XREAD         Random read from file to memory                  Real         34
  287.   PMXCREATE     Create file                                      Protected    35
  288.   PMXOPEN       Open existing file                               Protected    35
  289.   PMXCLOSE      Close file                                       Protected    35
  290.   PMXSAVE       Save memory to created file                      Protected    35
  291.   PMXLOAD       Load entire file to memory                       Protected    35
  292.   PMXWRITE      Random write from memory to file                 Protected    35
  293.   PMXREAD       Random read from file to memory                  Protected    35
  294.  
  295.   Descriptor Management Routines
  296.  
  297.   Name          Purpose                                          CPU Mode   Page
  298.   SETDESC       Place descriptor in local descriptor table       Real         36
  299.   PMSETDESC     Place descriptor in local descriptor table       Protected    36
  300.  
  301.   Debugging Routines (XLIBE only)
  302.  
  303.   Name          Purpose                                          CPU Mode   Page
  304.   SETWATCH      Set debug data watchpoint                        Real         43
  305.   FREEWATCH     Release debug data watchpoint                    Real         43
  306.   RESETWATCH    Release all debug data watchpoints               Real         44
  307.   PMSETWATCH    Set debug data watchpoint                        Protected    44
  308.   PMFREEWATCH   Release debug data watchpoint                    Protected    44
  309.   PMRESETWATCH  Release all debug data watchpoints               Protected    44
  310.  
  311.  
  312.  
  313.                                         v
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.                                  1. Introduction
  321.  
  322.  
  323.        XLIB is an assembly language library which enables protected-mode
  324.   programming under DOS.  XLIB services may be used by almost all programming
  325.   languages.  Despite its internal complexities, XLIB is a very simple to use.
  326.   For example, consider the following template for implementing the powerful 32-
  327.   bit flat model in assembly language:
  328.  
  329.  
  330.                  INCLUDE        FLAT.INC
  331.  
  332.   MAIN           PROC NEAR
  333.                  .
  334.                  .
  335.                  RET
  336.   MAIN           ENDP
  337.  
  338.                  [Other Procedures]
  339.  
  340.                  [Program Data]
  341.  
  342.                  END
  343.  
  344.  
  345.        The XLIB include file FLAT.INC will cause 32-bit protected-mode execution
  346.   to begin at a near procedure called MAIN.  Implementation of the flat model
  347.   merely requires that FLAT.INC be included as the first line of the program,
  348.   and that execution begin at a procedure called MAIN.
  349.        This template assumes a program that is entirely written in 32-bit
  350.   protected-mode assembly language.  Those developing such programs should read
  351.   the extensive comments in FLAT.INC and in the example program FLAT.ASM.
  352.   However, most programmers will need both real-mode and protected-mode
  353.   execution, and will generally need the services of a high-level language.
  354.   These situations are also easily accommodated by XLIB.
  355.        For those unfamiliar with assembly language, the XLIB archive contains a
  356.   second library called EASYX.  EASYX can be used by all high-level languages to
  357.   gain access to extended memory.
  358.        The archive also includes a library called XLIBE.  This library contains
  359.   all of the procedures in XLIB plus other procedures designed for debugging and
  360.   exception trapping.  XLIBE is capable of trapping exceptions in real mode
  361.   also; therefore, it is potentially useful even to programmers who would
  362.   otherwise have no interest in protected mode.
  363.        The archive for XLIB includes libraries and sample code in both Microsoft
  364.   and Borland formats.  XLIB has been successfully implemented with several
  365.   Borland and Microsoft languages.
  366.        XLIB is used to produce extended DOS applications.  DOS is unfortunately
  367.   limited by the fact that it is a real-mode operating system intended to manage
  368.   only real-mode programs.  Real-mode programs cannot use memory addresses
  369.   requiring more than 20 bits, or use memory offsets requiring more than 16
  370.   bits.  Such programs are further limited by the fact that 32-bit instructions
  371.   execute awkwardly in real-mode.  When the processor is in real-mode, it will
  372.   expect all 32-bit instructions to be preceded by at least one prefix.  Each of
  373.   these prefixes consumes one byte of memory and requires at least one clock to
  374.  
  375.  
  376.  
  377.                                         1
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.   execute.  Such limitations do not exist in 32-bit protected mode.  Extended
  385.   DOS applications overcome the limitations of DOS with their ability to execute
  386.   in both real and protected modes.  DOS services can be utilized from real mode
  387.   while the 32-bit powers of the CPU can be utilized from protected mode.
  388.        There are presently several 32-bit operating systems available on the
  389.   market.  Such systems include IBM's OS/2, Microsoft Windows NT, and UNIX.
  390.   These systems can manage programs which operate exclusively in protected mode.
  391.   There is little doubt that microcomputer programming is headed for a
  392.   protected-mode future.  However, it is not apparent at present which of these
  393.   operating systems will prevail as the future leader.  DOS is the dominant
  394.   system for the present, and this may be the case for some time because DOS is
  395.   a common thread linking these systems.  All these systems have DOS emulation
  396.   capabilities.  Extended DOS programs will almost equal the native programs of
  397.   these systems in power, and will far surpass them in compatibility.
  398.        Future programs will likely operate exclusively in protected mode using
  399.   the flat (unsegmented) memory model.  The memory models supported by XLIB
  400.   approximate the flat model; therefore, code written for XLIB will require
  401.   little modification when being transported to flat-model operating
  402.   environments.  Indeed, many procedures will require no modification
  403.   whatsoever.  Moreover, XLIB includes flat-model descriptors which may be used
  404.   to execute genuine flat-model code.  XLIB does not load and relocate such
  405.   code; however, it does provide the necessary tools to develop such procedures.
  406.        XLIB procedures handle important tasks such as mode switching between
  407.   real and protected modes, memory management under protected mode, protected-
  408.   mode interrupt management, and protected-mode file management.  XLIB includes
  409.   routines to perform these tasks in the absence of a protected-mode interface,
  410.   or in the presence of the Virtual Control Program Interface (VCPI), or the DOS
  411.   Protected Mode Interface (DPMI, version .9 or higher).  XLIB can also manage
  412.   extended memory through the Extended Memory Specification (XMS).  This
  413.   versatility makes XLIB compatible with nearly all common operating
  414.   environments for 386, 486, and Pentium processors.
  415.        XMS is the standard interface for managing extended memory.  HIMEM.SYS by
  416.   Microsoft is the most commonly known XMS driver.  VCPI is an older protected-
  417.   mode interface designed to coordinate possibly several protected-mode
  418.   programs.  VCPI is an optional subset of EMS (Expanded Memory Specification).
  419.   The most common VCPI driver is Microsoft's EMM386.SYS.  DPMI is the protected-
  420.   mode interface in Microsoft Windows and is considered the interface of the
  421.   future (though VCPI remains popular).  The more recent versions of Qualitas'
  422.   386MAX (version 6 and up) contain all of the above interfaces.  Quarterdeck's
  423.   QEMM386 contains XMS and VCPI.  Quarterdeck supplies DPMI in a second driver
  424.   called QDPMI.  The latter is supplied free of charge but requires QEMM386.
  425.        Upon initialization, XLIB will examine the operating environment for the
  426.   presence of DPMI, VCPI, and XMS, and then configure itself accordingly.  The
  427.   client program may therefore perform calls to XLIB procedures with few
  428.   concerns as to the environment in which it is executing.
  429.        This manual assumes the reader to have some degree of familiarity with
  430.   protected mode and a working knowledge of assembly language.  Those who are
  431.   not familiar with protected mode should read the tutorial in DONTREAD.ME.
  432.   This tutorial is quite informative.  Many readers will be able to bypass this
  433.   manual altogether after working through the tutorial.  Those unfamiliar with
  434.   assembly language should consider using the EASYX library.  This library is a
  435.   real-mode interface to XLIB.  It contains procedures which may be utilized
  436.   without assembly language.  The documentation for EASYX is included in the
  437.  
  438.  
  439.  
  440.  
  441.                                         2
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.   XLIB archive.  The reader might wish to refer to this documentation now;
  449.   however, the present document may still be needed for technical reference.
  450.        The following program illustrates the simplicity with which protected-
  451.   mode subroutines may be incorporated in real-mode programs using XLIB.  The
  452.   program was written with the Microsoft Assembler (MASM).  It first initializes
  453.   XLIB by calling a procedure called INITXLIB (initialize XLIB).  After
  454.   confirming that initialization is successful, the program then transfers
  455.   control to a 32-bit protected-mode procedure which prints a message to the
  456.   screen.  Control is transferred by placing the protected-mode target address
  457.   on the stack and then calling an XLIB procedure named CALLPM (call protected
  458.   mode).  CALLPM will expect the target procedure to be contained in a segment
  459.   called TSEG.  The protected-mode procedure in TSEG returns control to real or
  460.   virtual 8086 (V86) mode simply by executing the RET instruction.
  461.  
  462.  
  463.   Example 1:  Simple Mode Switching Under XLIB
  464.   _____________________________________________________________________________
  465.                  .MODEL        LARGE,PASCAL,FARSTACK
  466.                  .386
  467.                  INCLUDE        XLIB.INC       ;Include XLIB public symbols
  468.                  INCLUDELIB     XLIB.LIB       ;Link with XLIB.LIB
  469.                  .STACK         1024
  470.                  .CODE
  471.                  .STARTUP
  472.                  CALL           INITXLIB       ;Initialize XLIB
  473.                  OR             EAX,EAX        ;EAX = 0 if successful
  474.                  JZ             INITDONE
  475.                  .EXIT          0              ;Initialization failed
  476.   INITDONE:      PUSHD          OFFSET DEMOPROC
  477.                  CALL           CALLPM         ;Execute DEMOPROC in protected
  478.                  .EXIT          0
  479.  
  480.   ;Protected-mode routines must be placed in following segment:
  481.   TSEG           SEGMENT PARA PUBLIC USE32 'CODE'
  482.                  ASSUME CS:TSEG, SS:TSEG, DS:TSEG, ES:TSEG, FS:DSEG, GS:DGROUP
  483.  
  484.   ;Protected-mode routine to print message to the screen using DOS function.
  485.   DEMOPROC       PROC NEAR
  486.                  MOV            EBX,OFFSET PMMSG
  487.                  MOV            AH,02H
  488.   MSGLOOP:       MOV            DL,CS:[EBX]    ;32-bit offset!!!!!
  489.                  OR             DL,DL
  490.                  JZ             EXIT
  491.                  INT            21H            ;Print character with DOS
  492.                  INC            EBX
  493.                  JMP            MSGLOOP
  494.   EXIT:          RET                           ;Go back to real or V86 mode
  495.   PMMSG          DB  "In 32-bit protected mode!!!  "
  496.                  DB  "Returning to real mode.",10,13,0
  497.   DEMOPROC       ENDP
  498.  
  499.   TSEG           ENDS
  500.                  END
  501.   ____________________________________________________________________________
  502.  
  503.  
  504.  
  505.                                         3
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.        The framework presented in the above program is extremely simple;
  515.   nonetheless, it will meet the demands of many programs needing protected-mode.
  516.   Most protected-mode programs will require no further complications apart from
  517.   a few calls to XLIB extended memory management procedures.
  518.        XLIB relieves the programmer of descriptor table management by supplying
  519.   a set of predefined segments along with their associated descriptors and
  520.   selectors.  XLIB does allow user-defined descriptors, but these will seldom be
  521.   needed.  XLIB provides a single 32-bit segment called TSEG for protected-mode
  522.   routines.  This segment may be larger than 64K, but must reside in
  523.   conventional memory so that DOS can load it.  However, code within this
  524.   segment may access data throughout the address space.
  525.        To achieve the simplicity of the above program, XLIB must handle numerous
  526.   complexities internally.  This manual attempts to give the reader thorough
  527.   insight into the workings of XLIB.  It also discusses at length the numerous
  528.   configuration options that are available to the programmer.
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.                                         4
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.                         2. XLIB Conventions and Structure
  577.  
  578.  
  579.        The XLIB archive contains files for both Microsoft and Borland languages.
  580.   The files for Borland have the same names as those for Microsoft except a "B"
  581.   is added to the base name.  For example, XLIB.LIB is the XLIB library intended
  582.   for Microsoft languages whereas XLIBB.LIB is intended for Borland languages.
  583.   Sample code in this document is always for Microsoft languages; however,
  584.   Borland versions may be found in the archive.  Important information about
  585.   using XLIB with Microsoft and Borland languages has been included in the
  586.   README.DOC file.
  587.        All instructions pertaining to XLIB.LIB also pertain to XLIBE.LIB;
  588.   however, the latter library contains additional procedures for debugging and
  589.   for trapping processor exceptions.  XLIBE is intended for program development
  590.   while XLIB is intended for release versions.  The additional features in XLIBE
  591.   are discussed in Chapter 11.
  592.        The Microsoft version of XLIB was developed and tested under Microsoft
  593.   DOS version 6.2 using Microsoft Assembler (MASM) version 6.11, Microsoft LINK
  594.   version 5.31.009, and Microsoft LIB version 3.20.01.  The Borland version of
  595.   XLIB was developed and tested using Turbo Assembler (TASM) version 4.0, TLINK
  596.   version 6.0, and TLIB version 4.0.  XLIB was tested under Microsoft Windows
  597.   3.1, Qualitas 386MAX 7.01, Quarterdeck QEMM386 version 7.5, Quarterdeck QDPMI
  598.   1.06, and IBM OS/2 3.0.
  599.        XLIB public procedures and public data are explained in the following
  600.   chapters.  A detailed explanation of most XLIB public data is also included in
  601.   Appendix A.  This chapter sets forth rules which will be generally applicable
  602.   to all XLIB data and procedures.
  603.        Though it is sometimes necessary for XLIB to distinguish between real
  604.   mode and virtual 8086 mode; this document uses the term "real mode" to include
  605.   virtual 8086 mode.
  606.        All public real-mode procedures and 16-bit protected-mode procedures in
  607.   XLIB are located in a segment called CSEG.  The user may also place code in
  608.   CSEG but is rarely required to do so.  All public XLIB procedures in CSEG have
  609.   far returns (exceptions are noted in Appendix G).
  610.        All public 32-bit protected-mode procedures in XLIB are located in a 32-
  611.   bit segment called TSEG and have near returns.  XLIB will also expect the user
  612.   to place all 32-bit procedures in TSEG and will expect these procedures to
  613.   have near returns.  This policy is adopted to achieve approximation to the
  614.   flat model.
  615.        Nearly all XLIB protected-mode procedures are 32-bit routines.  The only
  616.   exceptions to this rule are the inline mode-switch procedures discussed in
  617.   Chapter 5.  This policy is implemented to approximate the flat model.  There
  618.   are very few circumstances in which 16-bit protected mode is preferable to 32-
  619.   bit protected mode.  One can generally increase program speed and reduce
  620.   program size by writing the code for 32-bit segments.
  621.        TSEG may be larger than 64K provided that certain rules are observed.
  622.   XLIB adheres to all of the necessary rules.  First, only 32-bit protected-mode
  623.   code should be placed in TSEG.  The processor will not generally be able to
  624.   execute real-mode code in this segment because the offsets will be 32-bit
  625.   values.  Second, real-mode code should never write to or read from TSEG.  Such
  626.   instructions will also require 32-bit offsets.  Modifications to TSEG should
  627.   be done from a TSEG protected-mode procedure.  Finally, segment constants
  628.   should never be encoded in TSEG.  For example, the symbols CSEG, TSEG, DSEG,
  629.   and DGROUP should not be found in TSEG.  DOS will not be able to perform
  630.  
  631.  
  632.  
  633.                                         5
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.   relocation edits on these constants if they are in a segment larger than 64K.
  641.   To read these values from TSEG, initialize memory locations in a 16-bit
  642.   segment to the values and then read the memory locations.  Memory locations in
  643.   DSEG have already been initialized for XLIB segments (see Appendix A).
  644.        Microsoft LINK will issue a warning for code segments exceeding 64K;
  645.   however, this warning may be safely ignored provided that the above rules are
  646.   observed.
  647.        TASM programmers should use the LARGESTACK directive for code in TSEG.
  648.   Without this directive, stack frames will be set up with BP and SP rather than
  649.   EBP and ESP.  The results could be disastrous if the high words of the 32-bit
  650.   registers are nonzero, as could be the case if TSEG exceeds 64K.
  651.        All XLIB procedures may be called with interrupts enabled.  An enabled
  652.   interrupt state will never be returned disabled.
  653.        With one exception, all XLIB public data is contained in a 16-bit segment
  654.   called DSEG.  The user may also place data in DSEG but is seldom required to
  655.   do so.
  656.        XLIB uses the PASCAL calling and naming convention.  The PASCAL
  657.   convention is equivalent to the BASIC and FORTRAN conventions.  C programmers
  658.   must adapt XLIB procedures and symbols with declarations which specify the
  659.   PASCAL convention.  The header file XLIB.H contains such declarations.
  660.        XLIB routines which can encounter error conditions will always return
  661.   XLIB error codes in AX.  A list of such error codes is presented in Appendix
  662.   B.  In most cases, DX or the high word of EAX will be returned with specific
  663.   information about the error, such as DPMI, XMS, or DOS error codes.  DPMI
  664.   error codes are presented in Appendix C.  XMS error codes are in Appendix D.
  665.        Selectors for all XLIB segments are placed in public WORD locations in
  666.   segment DSEG.  The following table gives the name of each predefined selector
  667.   along with its associated segment name and description:
  668.  
  669.  
  670.   Table 1:  XLIB Segments and Selectors by Public Symbol
  671.   _____________________________________________________________________________
  672.   Selector Name    Segment Name      Description
  673.   -------------    ------------      -----------
  674.   CSEGSEL          CSEG              XLIB 16-bit code segment
  675.   CSEGDSEL         CSEG              Data selector to CSEG
  676.   TSEGSEL          TSEG              32-bit code segment
  677.   TSEGDSEL         TSEG              Data selector to TSEG
  678.   DSEGSEL          DSEG              XLIB data segment
  679.   FLATSEL          .                 Flat-model code
  680.   FLATDSEL         .                 Flat-model data
  681.   DGROUPSEL        DGROUP            DGROUP data group
  682.   SCRNSEL          .                 Screen data
  683.   MAINCSSEL        .                 CS selector for main caller
  684.   MAINSSSEL        .                 SS selector for main caller
  685.   MAINDSSEL        .                 DS selector for main caller
  686.   MAINESSEL        .                 ES selector for main caller
  687.   ILCSSEL          .                 Inline CS selector
  688.   ILSSSEL          .                 Inline SS selector
  689.   ILDSSEL          .                 Inline DS selector
  690.   _____________________________________________________________________________
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.                                         6
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.        The flat-model and TSEG descriptors have limit FFFFFFFFH.  All other
  705.   descriptors have limit FFFFH.  The screen descriptor has base set to B8000H
  706.   for color monitors and B0000H for monochrome monitors.  MAINCSSEL, MAINSSEL,
  707.   MAINDSSEL, and MAINESSEL are selectors to descriptors which have base
  708.   addresses matching the contents of CS, SS, DS, and ES as of the call to
  709.   INITXLIB.  ILCSSEL, ILSSSEL, and ILDSSEL are selectors used by the inline
  710.   mode-switch procedures (see Chapter 5).  The base addresses of the
  711.   corresponding descriptors are adjusted dynamically.
  712.        All data segments are expand-up and writable.  Data descriptors also have
  713.   their big bits set; consequently, implicit stack instructions will use ESP
  714.   rather then SP.  All code segments are readable and nonconforming.  Descriptor
  715.   privilege levels and requested privilege levels are set to zero unless DPMI is
  716.   installed.  Privilege levels under DPMI will generally be set to three.
  717.        The values contained in the above selectors will be different under DPMI
  718.   than other environments.  Moreover, DPMI selector values can differ in
  719.   different environments and under different hosts.  Therefore, the user should
  720.   not assume these values to be constant.
  721.        Since selector values are stored in DSEG, the user must never lose track
  722.   of the DSEG selector.  This could prove a problem in interrupt handlers where
  723.   no assumptions can be made as to register contents.  Consequently, XLIB places
  724.   a copy of the DSEG selector in TSEG where it can always be found.  It is
  725.   stored under WORD symbol CSDSEGSEL and may be read with CS override.  For
  726.   example from TSEG code one can always load DS with DSEGSEL using MOV
  727.   DS,CS:CSDSEGSEL.
  728.        XLIB never uses selectors past DGROUPSEL in Table 1.  The user may
  729.   therefore redefine the associated descriptors if desired (see Chapter 9).
  730.   Selector values however should not be changed.
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.  
  754.  
  755.  
  756.  
  757.  
  758.  
  759.  
  760.  
  761.                                         7
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.                       3. XLIB Initialization and Termination
  769.  
  770.  
  771.        XLIB procedures apart from those presented in this chapter should be
  772.   called only after XLIB has been initialized by calling INITXLIB.  This routine
  773.   will examine the operating environment for the presence of DPMI, VCPI, and
  774.   XMS.  It will then perform extensive code modifications upon XLIB to
  775.   accommodate the resident software.  INITXLIB is to be called only once within
  776.   a program.  Subsequent calls have no effect.
  777.        If XLIB finds that neither DPMI nor VCPI are present, then XLIB will
  778.   completely handle all mode switching and interrupt management.  If XLIB finds
  779.   that XMS is absent also, then XLIB will handle all extended memory management.
  780.   If XLIB finds that both DPMI and VCPI are present, then it will configure
  781.   itself for DPMI by default.  However, the default may be changed by setting
  782.   bit 0 of IFLAGS (initialization flags) before calling INITXLIB.  If this bit
  783.   is set, then VCPI is given priority over DPMI.  IFLAGS is a public WORD
  784.   location in DSEG.
  785.        INITXLIB will possibly attempt to allocate some memory through DOS.
  786.   Since high-level language modules and assembly language modules often claim
  787.   all available conventional memory, INITXLIB may fail for lack of available
  788.   memory.  This problem can be averted with MASM programs by linking with the
  789.   CPARM:1 parameter.  This forces the program to claim no more conventional
  790.   memory than is necessary.  TASM programs and some high-level language programs
  791.   should release memory to DOS during initialization.  This process is
  792.   illustrated for TASM in the file EXAMP1B.ASM.  In some cases, the main program
  793.   will need to retain all memory except what is necessary for XLIB.  The XLIB
  794.   procedure XLIBMEMREQ (XLIB memory requirements) may be called to obtain
  795.   conventional memory requirements for XLIB.  Usage of XLIBMEMREQ is illustrated
  796.   for Microsoft BASIC in Chapter 10.  C and C++ do not allocate all conventional
  797.   memory and therefore do not require any special action.
  798.        If both VCPI and DPMI are present, then conventional memory requirements
  799.   will depend upon which of these interfaces is to be chosen by INITXLIB.  In
  800.   such cases, XLIBMEMREQ will return DPMI memory requirements if bit 0 of IFLAGS
  801.   is clear (the default), and will return VCPI requirements otherwise.
  802.   Therefore, this bit should be set to the appropriate value by the user before
  803.   calling XLIBMEMREQ.  DPMI conventional memory requirements may be obtained by
  804.   calling DPMIMEMREQ.  These will vary from host to host.  VCPI conventional
  805.   memory requirements may be obtained by calling VCPIMEMREQ.  VCPI requires
  806.   approximately 12K.
  807.        One of the principle functions of XLIB is of course to make protected-
  808.   mode interfaces and memory management interfaces transparent to the client
  809.   program.  However, there are special cases where a program should be informed
  810.   as to which interfaces are implemented.  In such cases, the procedure
  811.   XLIBCONFIG (XLIB configuration) may be called to determine the how XLIB has
  812.   been configured by INITXLIB.
  813.        XLIB is terminated with INT 21H function 4CH (DOS termination) issued
  814.   either from real or protected mode.
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.                                         8
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.   Detailed Specifications
  833.  
  834.  
  835.   INITXLIB (Initialize XLIB)
  836.   Purpose:  Check for presence of XMS, DPMI, and VCPI, then configure XLIB to
  837.   operate with the installed interfaces.
  838.   CPU Mode:  Real
  839.   Registers at Call:  None
  840.   Return Registers:
  841.      AX = 0 if successful, in which event DX and EAX are zero as well.  The
  842.   configured interfaces may be identified by calling XLIBCONFIG (see below).
  843.      AX <> 0 if unsuccessful.  An XLIB error code is returned in AX.  A specific
  844.   error code is returned in DX and in the high word of EAX (EAH).  If AX = 10H
  845.   or 11H, then a DOS error code is returned.  If AX = DPMI error, then a DPMI
  846.   1.0 error code is returned (if provided by host).  If AX = VCPI error, then DX
  847.   = EAH = 0.  If AX = XMS error, then an XMS error code is returned.
  848.   Details:
  849.      If both DPMI and VCPI are present and if EMS is enabled, then XLIB will be
  850.   configured for DPMI if the zero bit of IFLAGS is clear.  If this bit is set,
  851.   then XLIB will be configured for VCPI.  The bit is clear by default.  If EMS
  852.   is disabled, then XLIB will always be configured for DPMI if it is present.
  853.      This routine will possibly attempt to allocate conventional memory.  The
  854.   amount of memory XLIB will attempt to allocate can be obtained by calling
  855.   XLIBMEMREQ (see below).  The general address range from which this memory is
  856.   allocated can be controlled by appropriately setting the high byte of IFLAGS.
  857.   Alternative values for this byte are presented in Table 2.  The byte has a
  858.   value of 2 by default.  This setting forces XLIB to allocate from the highest
  859.   available address in conventional memory.  Under certain settings of IFLAGS,
  860.   XLIB can also allocate from upper memory (DOS 5.0 or higher).
  861.      Descriptors are created for the segments loaded in CS, SS, DS, and ES as of
  862.   call to this routine.  The selectors for these descriptors are MAINCSSEL,
  863.   MAINSSSEL, MAINDSSEL, and MAINESSEL.  These descriptors are never used by
  864.   other XLIB procedures.  They are provided to augment development of protected-
  865.   mode libraries.  Protected-mode library routines may access the stack and data
  866.   of the main program through these descriptors.
  867.      INITXLIB should be called only once within a program.  Subsequent calls are
  868.   returned with no action.  XLIB is terminated by INT 21H function 4CH (DOS
  869.   termination) issued from either real or protected mode.
  870.  
  871.  
  872.   Table 2:  IFLAGS Settings for Memory Allocation Control
  873.   _____________________________________________________________________________
  874.   Bits 8-15     Implied Memory Allocation Location
  875.   ---------     ----------------------------------
  876.   00H           Lowest available address in conventional memory (00000H-9FFFFH)
  877.   01H           Best fit in conventional memory
  878.   02H           Highest available address in conventional memory
  879.   40H           Lowest available address in upper memory (A0000H-FFFFFH)
  880.   41H           Best fit in upper memory
  881.   42H           Highest available address in upper memory
  882.   81H           Follow strategy 40H by 00H if necessary
  883.   82H           Follow strategy 41H by 01H if necessary
  884.   83H           Follow strategy 42H by 02H if necessary
  885.   _____________________________________________________________________________
  886.  
  887.  
  888.  
  889.                                         9
  890.  
  891.  
  892.  
  893.  
  894.  
  895.  
  896.   XLIBMEMREQ (XLIB Memory Requirements)
  897.   Purpose:  Find XLIB conventional memory requirements.
  898.   CPU Mode:  Real
  899.   Registers at Call:  None
  900.   Return Registers:
  901.      Sign bit of DX clear if successful.  Memory requirements in bytes are
  902.   returned in DX:AX.
  903.      Sign bit of DX set if unsuccessful.  An error code is returned in AX
  904.   (always a DOS error code).
  905.   Details:
  906.      DX:AX is adjusted upward to an integer multiple of 16.
  907.      If both DPMI and VCPI are present and if EMS is enabled, then XLIBMEMREQ
  908.   will assume that DPMI will be used if bit 0 of IFLAGS is clear (the default);
  909.   otherwise, VCPI is assumed.  If EMS is disabled, then DPMI will always be
  910.   assumed if present.  No additional conventional memory is needed if both DPMI
  911.   and VCPI are absent.
  912.      This routine will return DX:AX = 0 if XLIB contains free internal memory in
  913.   sufficient quantity to meet conventional memory demands.
  914.      This routine obtains DPMI requirements by calling DPMIMEMREQ (see below)
  915.   and VCPI requirements by calling VCPIMEMREQ.
  916.  
  917.   DPMIMEMREQ  (DPMI Memory Requirements)
  918.   Purpose:  Find DPMI conventional memory requirements.
  919.   CPU Mode:  Real
  920.   Registers at Call:  None
  921.   Return Registers:  DX:AX = conventional memory requirements.
  922.   Details:
  923.      DX:AX is adjusted upward to an integer multiple of 16.
  924.      This routine does not assume the presence of DPMI.  It will return DX:AX
  925.   set to zero if DPMI is absent.
  926.      This routine will return DX:AX = 0 if XLIB contains free internal memory in
  927.   sufficient quantity to meet the conventional memory demands of DPMI.
  928.  
  929.   VCPIMEMREQ (VCPI Memory Requirements)
  930.   Purpose:  Find VCPI conventional memory requirements.
  931.   CPU Mode:  Real
  932.   Registers at Call:  None
  933.   Return Registers:  DX:AX = conventional memory requirements.
  934.   Details:
  935.      DX:AX is adjusted upward to an integer multiple of 16.
  936.      This routine simply loads DX:AX with a constant approximately equal to
  937.   12Kb.
  938.  
  939.   XLIBCONFIG (XLIB Configuration)
  940.   Purpose:  Get XLIB configuration.
  941.   CPU Mode:  Real
  942.   Registers at Call:  None
  943.   Return Registers:  AX = 0 if protected-mode structures are not initialized;
  944.   otherwise, AX = XLIB configuration.  The value of lower nibble identifies the
  945.   protected-mode host/server.  If 1 then DPMI is installed.  If 2 then VCPI is
  946.   installed.  If 3 then XLIB handles mode switches.  Bit 4 is set if XMS is
  947.   installed.
  948.  
  949.  
  950.  
  951.  
  952.  
  953.                                         10
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960.                                 4. Mode Switching
  961.  
  962.  
  963.        As illustrated in Example 1, CALLPM may be used to transfer control to
  964.   32-bit protected mode in segment TSEG.  When execution is returned to real
  965.   mode, segment registers, ESP, system flags, and control flags are restored to
  966.   their original values.
  967.        Execution may also be transferred to protected mode in TSEG with the
  968.   ENTERPM (enter protected mode) procedure.  This procedure is specially
  969.   designed to accommodate mixed-language programming with high-level languages
  970.   operating in real mode.  High-level language modules may be linked with
  971.   libraries containing protected-mode procedures.  These procedures may then be
  972.   called from high-level code.  However, such procedures must generally be
  973.   careful to restore register state.  ENTERPM restores register state as
  974.   required by Microsoft high-level languages.  In particular, ENTERPM restores
  975.   all registers except EAX, EDX, and the status flags.  EAX and EDX are not
  976.   restored because these are typically used by high-level languages for return
  977.   values.  ENTERPM otherwise functions exactly as CALLPM.
  978.        Both CALLPM and ENTERPM save register state as of call.  CALLPM and
  979.   ENTERPM will also save and restore the state of the floating point unit (FPU)
  980.   if requested.  FPU save/restore can be enabled by setting bit 2 of OFLAGS
  981.   (operation flags).  The bit is clear by default.  OFLAGS is a public WORD in
  982.   DSEG.
  983.        FPU state is saved with the FSAVE instruction executed from real mode.
  984.   This instruction resets the FPU; consequently, the FPU control word must be
  985.   redefined.  XLIB will therefore load FPUCW (FPU control word) to the FPU
  986.   control word after performing FSAVE.  FPUCW is a public WORD location in DSEG.
  987.        After entering protected mode through CALLPM or ENTERPM, control would
  988.   typically be returned to real mode with the RET instruction.  However, control
  989.   may also be returned to real mode by jumping to either RETPM or EXITPM.  These
  990.   are both procedures in TSEG.  They will successfully return control to real
  991.   mode regardless of the stack state; therefore, they can be useful for
  992.   debugging.  For example, an unidentified area of protected-mode code that is
  993.   causing the system to crash can be isolated by placing jumps to EXITPM at
  994.   alternative locations.
  995.        RETPM returns control to the real-mode caller of CALLPM/ENTERPM after
  996.   restoring segment registers, ESP, system flags, and control flags.  EXITPM
  997.   returns control to the real mode caller after restoring all registers except
  998.   EAX, EDX, and the status flags.
  999.        The return address placed on the stack by CALLPM is actually a near
  1000.   return to RETPM.  Likewise, ENTERPM places a near return to EXITPM.  CALLPM
  1001.   and ENTERPM are otherwise identical procedures.
  1002.        Once within protected mode, far procedures in real mode can be called
  1003.   using CALLRM.  CALLRM may be called only by protected-mode procedures in TSEG.
  1004.        XLIB contains two hardware interrupt handlers that are typically
  1005.   activated upon entry to protected mode.  These handlers are fully explained in
  1006.   Chapter 6.  The first handler is hooked to the keyboard interrupt.  This
  1007.   handler manages hot key detection.  The second handler is hooked to the FPU
  1008.   interrupt and is designed to handle FPU exceptions.
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.                                         11
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.   Detailed Specifications
  1025.  
  1026.  
  1027.   CALLPM (Call Protected Mode)
  1028.   Purpose:  Call a protected-mode procedure in TSEG with near return.
  1029.   CPU Mode:  Real
  1030.   Registers at Call:  SS:ESP = 32-bit protected-mode target offset.
  1031.   Return Registers:  Returns through RETPM.  See RETPM for details.
  1032.   Details:
  1033.      All CPU registers except EAX and EDX are saved at locations presented in
  1034.   Table 3.  The stack is saved after removal of the return address and argument.
  1035.      The target receives SS = TSEGDSEL with 1000H free bytes on the stack.  The
  1036.   return address on the stack is a near return to RETPM.  The target receives by
  1037.   default:  DS = FLATDSEL, ES = TSEGDSEL, FS = DSEGSEL, and GS = DGROUPSEL.
  1038.   Other registers, including the status flags and interrupt flag, are received
  1039.   at values as of call.
  1040.      If bit 2 of OFLAGS is set, then the FPU state is also saved; the FPU is
  1041.   initialized, and FPUCW is loaded to the control word.
  1042.      The XLIB keyboard interrupt handler is enabled (see Chapter 6), and the FPU
  1043.   interrupt handler is enabled provided that bit 1 of OFLAGS is clear.
  1044.      If an FPU exception occurs after CALLPM, and if the FPU exception handler
  1045.   is enabled, then treatment of the exception will depend upon bit 3 in OFLAGS.
  1046.   If this bit is clear (the default), then a report of the exception will be
  1047.   displayed and the program will be terminated.  If the bit is set, then
  1048.   protected mode will be exited through EXITPM.  If FPU save/restore is not
  1049.   enabled, then real-mode will receive an initialized FPU with control word set
  1050.   to the value existing as of the exception.
  1051.      The user may change the stack after the mode switch.
  1052.      DS, ES, FS, and GS are actually loaded from:  PMDS, PMES, PMFS, and PMGS.
  1053.   These are public WORD locations in DSEG and are initialized to the default
  1054.   selectors by INITXLIB.  The user however may change these selectors to any
  1055.   legal values after initialization.
  1056.  
  1057.   RETPM (Return From Protected Mode)
  1058.   Purpose:  Return control to real mode with partial register restoration.
  1059.   CPU Mode:  Protected
  1060.   Registers at Call:  None
  1061.   Return Registers:  No return
  1062.   Details:
  1063.      RETPM switches to real mode and then restores all segment registers, ESP,
  1064.   system flags, and control flags to values as of call to either CALLPM or
  1065.   ENTERPM.  XLIB hardware interrupt handlers are disabled (see Chapter 6).
  1066.   Control is then transferred to the real-mode return address as of call to
  1067.   CALLPM/ENTERPM.
  1068.      If bit 2 of OFLAGS is set, then RETPM also restores FPU state.
  1069.      RETPM will successfully execute regardless of stack state.
  1070.  
  1071.   ENTERPM (Enter Protected Mode)
  1072.   Purpose:  Call a protected mode procedure in TSEG with near return.
  1073.   CPU Mode:  Real
  1074.   Registers at Call:  SS:ESP = 32-bit protected-mode target offset.
  1075.   Return Registers:  Returns through EXITPM.  See EXITPM for details.
  1076.   Details:  This routine executes exactly as CALLPM except that a near return to
  1077.   EXITPM is placed on the stack rather than to RETPM.
  1078.  
  1079.  
  1080.  
  1081.                                         12
  1082.  
  1083.  
  1084.  
  1085.  
  1086.  
  1087.  
  1088.   EXITPM (Exit Protected Mode)
  1089.   Purpose:  Return control to real mode with general register restoration.
  1090.   CPU Mode:  Protected
  1091.   Registers at Call:  None
  1092.   Return Registers:  No return
  1093.   Details:
  1094.      EXITPM switches to real mode and then restores all registers except EAX,
  1095.   EDX, and status flags to values as of call to either CALLPM or ENTERPM.  XLIB
  1096.   hardware interrupt handlers are disabled (see Chapter 6).  Control is then
  1097.   transferred to the real-mode return address as of call to CALLPM/ENTERPM.
  1098.      If bit 2 of OFLAGS is set, then EXITPM also restores FPU state.
  1099.      EXITPM will successfully execute regardless of stack state.
  1100.      The FPU exception handler performs a jump to EXITPM upon occurrence of any
  1101.   unmasked FPU exception.
  1102.  
  1103.  
  1104.   Table 3:  CALLPM/ENTERPM Register Storage Locations by Public Symbol
  1105.   _____________________________________________________________________________
  1106.   Register           Symbol              Symbol Type
  1107.   --------           ------              -----------
  1108.   EBX                ORGEBX              DWORD
  1109.   ECX                ORGECX              DWORD
  1110.   ESI                ORGESI              DWORD
  1111.   EDI                ORGEDI              DWORD
  1112.   EBP                ORGEBP              DWORD
  1113.   ESP                ORGESP              DWORD
  1114.   EFLAGS             ORGEFLAGS           DWORD
  1115.   SS                 ORGSS               WORD
  1116.   DS                 ORGDS               WORD
  1117.   ES                 ORGES               WORD
  1118.   FS                 ORGFS               WORD
  1119.   GS                 ORGGS               WORD
  1120.   FPU State          ORGFPU              BYTE[94]
  1121.   _____________________________________________________________________________
  1122.  
  1123.  
  1124.   CALLRM (Call a Real-Mode Procedure)
  1125.   Purpose:  Call a real-mode routine with far return from protected mode.
  1126.   CPU Mode:  Protected
  1127.   Registers at Call:  SS:ESP = far real-mode target address (four bytes).
  1128.   Return Registers:  All segment registers and ESP are restored.  Other
  1129.   registers, including status flags and the interrupt flag, are received with
  1130.   values as of the real-mode RET instruction.
  1131.   Details:
  1132.      This is a near procedure in TSEG.  It must therefore be called from TSEG.
  1133.      Segment registers and ESP are saved at locations presented in Table 4.  The
  1134.   stack is saved after popping the return address and argument.
  1135.      The target receives the XLIB real-mode stack (SS = DSEG) with 200H free
  1136.   bytes.  By default, the target receives DS = DGROUP, ES = DSEG, FS = DSEG, and
  1137.   GS = DSEG.  Other registers, including status flags and the interrupt flag,
  1138.   are received at values as of call.
  1139.      Code called by this routine should not perform calls to XLIB procedures
  1140.   other than SWITCHPM and SWITCHRM (see Appendix G).  Most real-mode procedures
  1141.  
  1142.  
  1143.  
  1144.  
  1145.                                         13
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.   in XLIB issue calls to CALLPM; however, neither CALLPM nor ENTERPM are
  1153.   reentrant.  For example, you cannot nest CALLPM/RETPM pairs.
  1154.      DS and ES are actually loaded from RMDS and RMES.  These are public WORD
  1155.   locations in DSEG and are initialized to the default values.  However, the
  1156.   user may change these values if desired.
  1157.      This procedure does not change values in OFLAGS; consequently, XLIB
  1158.   hardware interrupt handlers remain enabled in real mode if they were enabled
  1159.   as of call (see Chapter 6).
  1160.      FPU exceptions in real mode are handled the same as in protected mode;
  1161.   however, system software is less apt to be left in regular state after real-
  1162.   mode exceptions.  FPU instructions should therefore be executed in protected
  1163.   mode where possible.
  1164.  
  1165.  
  1166.   Table 4:  CALLRM Register Storage Locations by Public Symbol
  1167.   _____________________________________________________________________________
  1168.   Register           Symbol              Symbol Type
  1169.   --------           ------              -----------
  1170.   ESP                CALLESP             DWORD
  1171.   SS                 CALLSS              WORD
  1172.   DS                 CALLDS              WORD
  1173.   ES                 CALLES              WORD
  1174.   FS                 CALLFS              WORD
  1175.   GS                 CALLGS              WORD
  1176.   _____________________________________________________________________________
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.                                         14
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216.                              5. Inline Mode Switching
  1217.  
  1218.  
  1219.        XLIB includes two routines to perform mode switching in C and C++
  1220.   programs using inline assembly.  These procedures are very versatile and
  1221.   simple.  They switch the processor between real mode and 16-bit protected
  1222.   mode.  A third routine is included to facilitate calls from 16-bit protected-
  1223.   mode to 32-bit near procedures in TSEG.
  1224.        Call INLINEPM to switch to 16-bit protected mode.  Descriptors are
  1225.   automatically created for CS, SS, and DS.  These registers are returned
  1226.   containing selectors to the respective descriptors.  ES is returned containing
  1227.   DSEGSEL.  ES may therefore be used to load other XLIB selectors to segment
  1228.   registers.
  1229.        Call INLINERM to return to real-mode.  This function should be called
  1230.   from the same segment as the previous call to INLINEPM and should be using the
  1231.   same stack segment.  INLINERM restores segment registers to values which
  1232.   existed as of the call to INLINEPM.
  1233.        The following Microsoft C 7.0 program illustrates the usage of these
  1234.   procedures.  The program contains a C subroutine called "getextmem" which uses
  1235.   INLINEPM and INLINERM to retrieve a DWORD from extended memory.
  1236.        Since the Microsoft C 7.0 compiler does not recognize 32-bit assembly
  1237.   instructions, the following program attains access to 32-bit registers by
  1238.   encoding prefixes in front of 16-bit instructions.  These prefixes are
  1239.   inserted with the _emit directive.  Also observe that INLINERM is called
  1240.   indirect through a supplied pointer in DSEG called INLINERMPTR.  This is done
  1241.   to ensure that the intersegment call loads CS with the protected-mode selector
  1242.   for CSEG (CSEGSEL) rather than with the segment constant.
  1243.        A Borland C version of this program is contained in the file EXAMP2B.C.
  1244.   The Borland version is somewhat simpler than the following program because 32-
  1245.   bit registers can be used in Borland C provided that TASM is used to perform
  1246.   the assembly.
  1247.        This program may fail if an attempt is made to access logical addresses
  1248.   which are either protected or undefined in the page tables.
  1249.  
  1250.  
  1251.  
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.  
  1258.  
  1259.  
  1260.  
  1261.  
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.  
  1272.  
  1273.                                         15
  1274.  
  1275.  
  1276.  
  1277.  
  1278.  
  1279.  
  1280.   Example 2:  Using INLINEPM/INLINERM in C
  1281.   _____________________________________________________________________________
  1282.   #include <stdio.h>
  1283.   #include <xlib.h>
  1284.   #define som _emit 0x66               /*Switch operand mode*/
  1285.   #define sam _emit 0x67               /*Switch address mode*/
  1286.   unsigned long __far getextmem(unsigned long address);
  1287.   int goterr = 0;                      /*Error flag*/
  1288.  
  1289.   void main(void)
  1290.   {
  1291.     unsigned long l, xaddress;
  1292.     l = INITXLIB();                    /*Initialize XLIB*/
  1293.     if(l != 0)                         /*See if an error occurred*/
  1294.     {
  1295.       printf("Library initialization error:  %lX\n",l);
  1296.       return;
  1297.     }
  1298.  
  1299.     xaddress = 0x100000;               /*Read first dword in 2ond meg*/
  1300.     l = getextmem(xaddress);           /*See if an error occurred*/
  1301.     if(goterr != 0)
  1302.     {
  1303.       printf("Inline mode-switch error:  %lX\n",l);
  1304.       return;
  1305.     }
  1306.     printf("[%lX] = %lX\n",xaddress,l);
  1307.   }
  1308.  
  1309.   unsigned long __far getextmem(unsigned long address)
  1310.   {
  1311.     __asm
  1312.     {
  1313.       som                             ;mov  eax,[bp+6]
  1314.       mov       ax,[bp+6]             ;  ""
  1315.       call      INLINEPM              ;Switch to 16-bit protected mode
  1316.       jc        error                 ;Error code in ax
  1317.       mov       ds,es:FLATDSEL        ;Switch to flat data model
  1318.       sam                             ;push dword ptr [eax]
  1319.       som                             ;  ""
  1320.       _emit     0ffh                  ;  ""
  1321.       _emit     030h                  ;  ""
  1322.       pop       ax                    ;Return address contents in dx:ax
  1323.       pop       dx
  1324.       call      es:INLINERMPTR        ;Switch back to real mode by calling
  1325.       jmp       done                  ;INLINERM indirect.  A direct call would
  1326.                                       ;load cs with an invalid value.
  1327.   error:
  1328.       xor       dx,dx                 ;Return error code in dx:ax
  1329.       inc       goterr                ;Set error flag
  1330.   done:
  1331.     }
  1332.   }
  1333.   _____________________________________________________________________________
  1334.  
  1335.  
  1336.  
  1337.                                         16
  1338.  
  1339.  
  1340.  
  1341.  
  1342.  
  1343.  
  1344.   Detailed Specifications
  1345.  
  1346.  
  1347.   INLINEPM (Inline Protected-Mode)
  1348.   Purpose:  Return to real-mode caller in 16-bit protected mode.
  1349.   CPU Mode:  Real
  1350.   Registers at Call:  None
  1351.   Return Registers:
  1352.      CF clear if successful.  Descriptors are created for CS, SS, and DS.  These
  1353.   descriptors have base addresses matching the calling contents of the
  1354.   respective segment registers.  The segment registers are returned containing
  1355.   selectors to these descriptors.  These selectors are also stored in DSEG at
  1356.   the public WORD locations ILCSSEL, ILSSSEL, and ILDSSEL.  See Chapter 2 for
  1357.   further details as to descriptor specifications.  ES, FS, and GS are returned
  1358.   containing DSEGSEL.  Protected mode receives other registers, except the
  1359.   status flags, at values as of call.  System flags (including the interrupt
  1360.   flag) and control flags are preserved through the call.
  1361.      CF set if unsuccessful.  The processor will still be in real mode.
  1362.   Unsuccessful execution can occur only under DPMI.  EAX is returned with an
  1363.   error code.  AX = XLIB error code.  The high word of EAX will equal a DPMI 1.0
  1364.   error code (if provided by host).  Other registers, except the status flags,
  1365.   are unchanged.
  1366.   Details:
  1367.      INLINEPM stores segment registers at the same locations used by CALLPM and
  1368.   ENTERPM (Table 1).  INLINERM (see below) then restores these registers.  C
  1369.   will require that other registers be preserved also; however, the user is
  1370.   responsible for managing these.
  1371.      XLIB hardware interrupt handlers are not activated by this procedure (see
  1372.   Chapter 6).  The user may enable them by setting bit 0 of OFLAGS; however, bit
  1373.   3 of OFLAGS should be clear.  When this bit is clear, the FPU interrupt
  1374.   handler displays a report of the exception and then terminates the program.
  1375.   When the bit is set, the handler sends an error code back to real mode via
  1376.   EXITPM.  However, EXITPM will fail in this case because protected mode was not
  1377.   entered through ENTERPM or CALLPM.  The FPU interrupt handler may be
  1378.   altogether disabled by setting bit 1 of OFLAGS.
  1379.      SP is preserved through the mode switch; however, the high word of ESP is
  1380.   set to zero.  The high word must be cleared since SS is set to a descriptor
  1381.   having FFFFH limit and having its big bit set.
  1382.      If multiple calls are made to INLINEPM with no changes to CS, SS, and DS,
  1383.   then descriptors are created only on the first call.  Subsequent calls will
  1384.   therefore execute more quickly.
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.                                         17
  1402.  
  1403.  
  1404.  
  1405.  
  1406.  
  1407.  
  1408.   INLINERM (Inline Real-Mode)
  1409.   Purpose:  Return to 16-bit protected-mode caller in real mode.
  1410.   CPU Mode:  16-bit protected mode
  1411.   Registers at Call:  CS and SS must equal values as of return from INLINEPM.
  1412.   Return Registers:  Segment registers are restored to values existing as of
  1413.   former call to INLINEPM.  Real mode receives other registers, except status
  1414.   flags, at values as of call.  System flags (including the interrupt flag) and
  1415.   control flags are preserved through the call.
  1416.   Details:
  1417.      Since INLINERM will be called intersegment, caution must be taken that CS
  1418.   is loaded with CSEGSEL and not CSEG.  XLIB provides a far pointer to this
  1419.   procedure called INLINERMPTR which may be used to execute the call.
  1420.      INLINERM and CALL32 are the only 16-bit protected-mode procedures in XLIB.
  1421.   They are also the only protected-mode procedures having far returns.
  1422.  
  1423.   CALL32 (Call 32-bit Protected-Mode)
  1424.   Purpose:  Call a 32-bit protected-mode near procedure in segment TSEG from 16-
  1425.   bit protected-mode.
  1426.   CPU Mode:  16-bit protected mode
  1427.   Registers at Call:  SS:ESP =  32-bit protected-mode target offset.
  1428.   Return Registers:  All registers, including status flags, are returned with
  1429.   values existing as of the 32-bit RET instruction.
  1430.   Details:
  1431.      CALL32 is a far procedure; therefore, caution must be taken that calls to
  1432.   CALL32 load CS with CSEGSEL instead of CSEG.  XLIB provides a far pointer to
  1433.   this procedure in DSEG called CALL32PTR which may be used to execute the call.
  1434.      CALL32 and INLINERM are the only 16-bit protected-mode procedures in XLIB.
  1435.   They are also the only protected-mode procedures having far returns.
  1436.      This procedure does not alter the state of OFLAGS.
  1437.  
  1438.  
  1439.  
  1440.  
  1441.  
  1442.  
  1443.  
  1444.  
  1445.  
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454.  
  1455.  
  1456.  
  1457.  
  1458.  
  1459.  
  1460.  
  1461.  
  1462.  
  1463.  
  1464.  
  1465.                                         18
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471.  
  1472.                              6. Interrupt Management
  1473.  
  1474.  
  1475.        Interrupt management is the most complicated task performed by XLIB.
  1476.   Accordingly, this chapter is the most difficult section of the user's manual.
  1477.   In general, this chapter may be ignored for programs which do not install
  1478.   interrupt handlers, do not require hot key detection, and do not use floating
  1479.   point operations.
  1480.  
  1481.  
  1482.   XLIB Interrupt Handlers
  1483.  
  1484.  
  1485.        XLIB handles nearly all interrupts occurring in protected mode by
  1486.   shifting to real mode and calling the currently installed real-mode interrupt
  1487.   handlers.  In all but five cases, XLIB uses inherited real-mode handlers.
  1488.   XLIB installs its own handlers for the DOS interrupt (INT 21H), the CTRL C
  1489.   interrupt (INT 23H), the DOS critical error interrupt (INT 24H), the keyboard
  1490.   interrupt (INT 9), and the FPU interrupt (INT 75H).
  1491.        The DOS interrupt handler (INT 21H) intercepts all DOS calls and
  1492.   determines if termination is requested (AH = 4CH).  If not, then the interrupt
  1493.   is immediately cascaded to DOS.  If so, then XLIB performs housecleaning
  1494.   before relaying the request to DOS.  Under DPMI, XLIB will restore all
  1495.   interrupt vectors and release all allocated descriptors.  The DPMI host
  1496.   automatically releases all allocated memory.  Under other configurations, XLIB
  1497.   will reset all real-mode interrupt vectors and release all allocated extended
  1498.   memory.
  1499.        The DOS handlers for INT 23H (CTRL C) and INT 24H (DOS critical error)
  1500.   may attempt to terminate a program by means other than INT 21H function 4CH.
  1501.   Consequently, XLIB installs its own handlers for these routines to ensure
  1502.   proper termination.
  1503.        INT 21H function 4CH may be executed in either real mode or protected
  1504.   mode.  DPMI hosts will expect this function to be executed from protected
  1505.   mode; consequently, XLIB will switch to protected mode before relaying the
  1506.   request to DPMI.  XLIB also installs a protected-mode handler for INT 21H
  1507.   under DPMI.  This is to ensure that XLIB will see the termination request
  1508.   before the DPMI host.
  1509.        The keyboard interrupt handler is intended to facilitate termination of
  1510.   protected-mode procedures with a keypress.  When a user-defined hot key is
  1511.   pressed, the keyboard interrupt handler will modify a flag variable.  This
  1512.   flag variable may then be polled periodically in the main thread of execution.
  1513.   The keyboard interrupt handler is a real-mode routine.
  1514.        The inconvenience of having to poll the flag variable is unfortunately
  1515.   necessary.  It is not generally safe to terminate within a hardware interrupt
  1516.   handler, particularly in protected-mode environments.  A hardware interrupt
  1517.   generated by a keypress may have interrupted system software in the middle of
  1518.   a system maintenance operation.  Termination in such cases would likely leave
  1519.   the system in an irregular and potentially unstable state.
  1520.        Matters are further complicated in most protected-mode environments.  For
  1521.   example, a DPMI host will trap all hardware interrupts before cascading them
  1522.   to interrupt handlers.  If control is not returned to the host with the IRET
  1523.   instruction, then the host could be left in an irregular state.  Moreover, the
  1524.   trapping procedure will likely switch stacks before relaying the interrupt to
  1525.   the handler; consequently, the handler cannot determine the final return
  1526.  
  1527.  
  1528.  
  1529.                                         19
  1530.  
  1531.  
  1532.  
  1533.  
  1534.  
  1535.  
  1536.   address and therefore cannot change this address to a termination procedure.
  1537.   These complications will nearly always occur when hardware interrupts are
  1538.   virtualized.  Virtual 8086 mode interrupts will almost certainly be
  1539.   virtualized in either VCPI-based or DPMI-based environments.
  1540.        When a key is pressed, the keyboard interrupt handler will examine the
  1541.   key to determine if it is the hot key.  If not, then the interrupt is cascaded
  1542.   to the inherited real-mode handler.  If so, then a hot key flag is recorded to
  1543.   a DWORD whose linear address is recorded at CCODEPTR (condition code pointer).
  1544.   The hot key is not cascaded.  CCODEPTR is a public DWORD in DSEG.  The hot key
  1545.   flag is listed among XLIB error codes in Appendix B.
  1546.        CCODEPTR initially contains the linear address to public DWORD location
  1547.   CCODE which is in DSEG.  Therefore, the hot key flag would be written to CCODE
  1548.   by default.  CCODEPTR may be changed by the user; however, it must point to an
  1549.   address in conventional memory.
  1550.        The hot key specification is stored in DSEG at a public WORD location
  1551.   called HOTKEY.  The lower byte of HOTKEY contains the scan code of the hot key
  1552.   while the upper byte specifies the state of the shift keys.  Bit 8 specifies
  1553.   the state of SHIFT; bit 9 specifies CTRL, and bit 10 specifies ALT.  All other
  1554.   bits are ignored.  Set bits require that the designated shift key be pressed.
  1555.   The default setting for HOTKEY is zero.  This setting disables hot key
  1556.   detection since no key has a zero scan code.
  1557.        The behavior of the XLIB FPU interrupt handler will depend upon the value
  1558.   of bit 3 in OFLAGS.  If this bit is clear (the default), then the handler will
  1559.   display a report of the exception and then terminate the program.  The FPU
  1560.   will be initialized before termination.  If bit 3 of OFLAGS is set, then the
  1561.   handler transfers control to EXITPM, which then returns to the real-mode
  1562.   caller of CALLP or ENTERPM.  Before the transfer, the handler will place an
  1563.   error code in EAX and at the linear address contained in CCODEPTR.  It will
  1564.   also initialize the FPU (the FPU control word is preserved).
  1565.        The high word of error codes returned by the FPU exception handler will
  1566.   contain the FPU status word.  The status word may be examined to determine the
  1567.   nature of the exception.  The exception handler will also record the FPU state
  1568.   in FPUSTATE before transferring control to real mode.  FPUSTATE may be
  1569.   examined to determine the exact nature of the exception, and may be reloaded
  1570.   to completely restore the FPU state existing as of the exception.  FPUSTATE is
  1571.   a public BYTE array in DSEG.
  1572.        The response of the FPU to exception conditions is largely determined by
  1573.   the settings in the FPU control word.  If FPU save/restore is enabled, then
  1574.   the FPU control word will be set to FPUCW upon execution of CALLPM or ENTERPM.
  1575.   The default value for FPUCW is 0332H.  This sets rounding control to nearest,
  1576.   precision control to 64 bits, and unmasks exceptions for overflow, zero
  1577.   divide, and invalid operations.  Exceptions for underflow, precision, and
  1578.   denormalized operations are masked, and are therefore handled internally by
  1579.   the FPU.  FPUCW may be modified by the user.
  1580.        As explained above, the machine may be left in an unstable state after a
  1581.   program has been terminated from within a hardware interrupt handler.  This
  1582.   can also be the case for the FPU interrupt handler.  However, it will be safe
  1583.   to continue execution after FPU exceptions under clean configurations.  This
  1584.   follows because interrupts are not virtualized and because the exception will
  1585.   never be generated in the operating system (DOS seldom uses the FPU).  Nor
  1586.   should there be any problem with continuing execution after an exception in
  1587.   protected-mode under VCPI.  This follows since protected-mode interrupts
  1588.   cannot be virtualized under VCPI.  Exceptions occurring in virtual 8086 mode
  1589.   or under DPMI protected mode may however leave the machine in an irregular
  1590.  
  1591.  
  1592.  
  1593.                                         20
  1594.  
  1595.  
  1596.  
  1597.  
  1598.  
  1599.  
  1600.   state.  Reboot may be necessary in such cases; however, experience indicates
  1601.   that this is very rare.
  1602.        Bit 0 of OFLAGS is used by XLIB to simultaneously enable or disable all
  1603.   of its own hardware interrupt handlers.  Setting the bit enables the handlers.
  1604.   XLIB sets this bit upon calls to CALLPM or ENTERPM and clears the bit upon
  1605.   return.  All hardware interrupts are immediately cascaded to the inherited
  1606.   real-mode handlers when the bit is clear.  Therefore, FPU exceptions are
  1607.   handled by XLIB only after calls to CALLPM or ENTERPM.  Accordingly, hot key
  1608.   detection is enabled only after calls to CALLPM or ENTERPM.  The user may set
  1609.   the bit under other circumstances; however, either bit 3 of OFLAGS should be
  1610.   clear or bit 1 of OFLAGS (see next paragraph) should be set.  Without these
  1611.   settings, the FPU interrupt handler will attempt a transfer to real mode
  1612.   through EXITPM.  This transfer will fail because protected mode was not
  1613.   entered through CALLPM or ENTERPM.
  1614.        The FPU exception handler may be permanently disabled by setting bit 1 in
  1615.   OFLAGS.  If this bit is set, then the FPU interrupt handler simply cascades
  1616.   the interrupt to the inherited real-mode handler.  XLIB will set the bit
  1617.   during initialization if an FPU is not present; it is otherwise cleared.
  1618.        Real-mode software interrupts which receive or return values in segment
  1619.   registers cannot be used within protected mode because the deflection routine
  1620.   will restore selectors to segment registers upon completion of the interrupt.
  1621.   To use such software interrupts, one must switch to real mode through CALLRM;
  1622.   issue the interrupt, and then transfer the segment registers to other
  1623.   registers or to memory before returning to protected mode.
  1624.        Certain software interrupts use status flags for return flags, typically
  1625.   to signal error conditions.  This is particularly the case for DOS interrupts.
  1626.   The deflection routine will pass these alterations to the code which issued
  1627.   the interrupt.
  1628.  
  1629.  
  1630.   Installation of Interrupt Handlers
  1631.  
  1632.  
  1633.        The user may install real-mode interrupt handlers in usual fashion.  Such
  1634.   handlers will also receive interrupts occurring in protected mode because
  1635.   either XLIB or the DPMI host will deflect all protected-mode interrupts.  If
  1636.   XLIB deflects the interrupt, then the handler will receive SS = DSEG with ESP
  1637.   set to 200H free bytes.  Stack sizes under DPMI will depend upon the host, but
  1638.   must contain a minimum of 200H free bytes to meet DPMI specifications.
  1639.        The DOS routines to get and set interrupt vectors (INT 21H functions 35H
  1640.   and 25H) receive and return values through segment registers; consequently,
  1641.   they cannot be used in protected mode.  Instead, use the XLIB procedures
  1642.   PMGETRMIV and PMSETRMIV (protected mode - get/set real-mode interrupt vector).
  1643.        The user may install a protected-mode interrupt handler from real mode by
  1644.   calling SETPMIV (set protected-mode interrupt vector).  The current protected-
  1645.   mode interrupt vector may be obtained by calling GETPMIV.
  1646.        From protected mode, interrupt vectors can be managed with PMSETPMIV and
  1647.   PMGETPMIV.  These procedures have the same specifications as SETPMIV and
  1648.   GETPMIV.
  1649.        Interrupt handlers installed with SETPMIV/PMSETPMIV are never disabled by
  1650.   XLIB and will therefore always be active under protected-mode execution.
  1651.   These handlers will not be active under real-mode execution in the absence of
  1652.   DPMI.  That is, real-mode interrupts are never deflected to protected-mode
  1653.   handlers in such environments.  However if DPMI is active, then all hardware
  1654.  
  1655.  
  1656.  
  1657.                                         21
  1658.  
  1659.  
  1660.  
  1661.  
  1662.  
  1663.  
  1664.   interrupts (IRQs 0-15) and the software interrupts:  1CH (BIOS timer tick),
  1665.   23H (DOS CTRL C), and 24H (DOS critical error) are deflected from real mode to
  1666.   the installed protected-mode handler.  Therefore the protected-mode handler
  1667.   always receives the interrupt first.  If the handler cascades the interrupt,
  1668.   then the real-mode handler will receive it next.  If the user has not
  1669.   installed protected-mode handlers for these interrupts, then they are serviced
  1670.   by default handlers in the DPMI host.  The default handlers typically deflect
  1671.   the interrupts to the real-mode handlers.
  1672.        If the programmer wishes to install a protected-mode interrupt handler
  1673.   for a hardware interrupt or for INT 1CH, INT 23H, or INT 24H, then
  1674.   consideration must be given to the fact that treatment of these interrupts
  1675.   will differ under different protected-mode configurations.  As noted above,
  1676.   the DPMI host will always send these interrupts to the protected-mode handler
  1677.   regardless of the CPU mode in which the interrupt occurred.  If DPMI is not
  1678.   installed, then protected-mode handlers receive control only under protected-
  1679.   mode interrupts.  Therefore, if the protected-mode handler is to receive real-
  1680.   mode interrupts under such configurations, the programmer must install a real-
  1681.   mode handler to perform the deflection.
  1682.        XLIB includes a procedure called DEFLECTPM which can be used within a
  1683.   real-mode interrupt handler to deflect control to a protected-mode handler.
  1684.   DEFLECTPM functions only under VCPI and XLIB mode switching.  If DPMI is
  1685.   installed, then the procedure returns with no action.  The intent of this
  1686.   procedure is to enable simulation of DPMI treatment of hardware interrupts,
  1687.   INT 1CH, INT 23H, and INT 24H.
  1688.        Observe that if the real-mode handler deflects to the protected-mode
  1689.   handler, then the latter should not cascade the interrupt since an infinite
  1690.   loop would result.  This follows because the initial protected-mode handler
  1691.   deflects to the real-mode handler.
  1692.        Were one to use DEFLECTPM in a real-mode handler for the interrupts named
  1693.   above, then the protected-mode handler will receive all interrupts regardless
  1694.   of the protected-mode configuration.  This occurs naturally under DPMI.
  1695.   DEFLECTPM ensures that it will occur under other configurations.  Observe that
  1696.   under DPMI, the real-mode handler will never be executed.
  1697.        A real-mode interrupt handler may need to perform shifts to protected
  1698.   mode in order to gain access to extended memory.  This mode switch should not
  1699.   be performed with CALLPM or ENTERPM if there is any possibility that the
  1700.   interrupt originated in protected mode or during a call through CALLRM.  This
  1701.   follows because CALLPM and ENTERPM are not reentrant; consequently, calls to
  1702.   these procedures cannot be nested.  The same may be said of INLINEPM and
  1703.   INLINERM.  Use the SWITCHPM and SWITCHRM procedures discussed in Appendix G
  1704.   for this purpose.
  1705.        Real-mode hardware interrupt handlers which perform shifts to protected
  1706.   mode should be installed after the call to INITXLIB.  Otherwise, the first
  1707.   interrupt may occur before protected-mode structures and code have been
  1708.   initialized.
  1709.        Interrupt handlers should never call XLIB procedures apart from
  1710.   DEFLECTPM, SWITCHPM, and SWITCHRM.  This limitation applies to handlers in
  1711.   either CPU mode.
  1712.        It is sometimes important that interrupt handlers execute in shortest
  1713.   possible CPU time.  This would typically be the case for handlers of the
  1714.   communication ports.  Since mode switching is time consuming, such handlers
  1715.   should be installed for the CPU mode which is expected to receive the most
  1716.   interrupts.
  1717.  
  1718.  
  1719.  
  1720.  
  1721.                                         22
  1722.  
  1723.  
  1724.  
  1725.  
  1726.  
  1727.  
  1728.        If DPMI is installed, then it is possible for multiple clients to operate
  1729.   in a single virtual machine.  In such cases, DPMI will always send hardware
  1730.   interrupts to the primary client (the most recently installed client in the
  1731.   virtual machine).
  1732.        Under DPMI, all protected-mode handlers for hardware interrupts and
  1733.   software interrupts 0-7 will receive control with interrupts disabled.  Since
  1734.   DPMI virtualizes the interrupt flag, the IRET instruction may not reenable
  1735.   interrupts.  Consequently, all handlers for these interrupts should execute
  1736.   STI before executing IRET.  Other protected-mode interrupts do not affect the
  1737.   interrupt flag.
  1738.        All real-mode interrupt handlers will receive control with interrupts
  1739.   disabled regardless of the protected-mode configuration.  All protected-mode
  1740.   handlers will receive control with interrupts disabled under VCPI or XLIB mode
  1741.   switching.  However, if DPMI is installed, then protected-mode software
  1742.   interrupts apart from 0-7 will receive the virtual interrupt flag at its value
  1743.   as of the INT instruction.  That is, DPMI does not alter the interrupt flag in
  1744.   these cases.
  1745.        Hardware interrupts IRQ 0 through IRQ 7 are typically assigned to
  1746.   interrupt numbers 08H through 0FH, while IRQs 8 through 15 are typically
  1747.   assigned interrupt numbers 70H through 77H.  However, IRQs are remapped in
  1748.   some operating environments, typically to facilitate exception handling.
  1749.   XLIBE will in fact remap hardware interrupts in some situations (see Chapter
  1750.   11).  The current mappings may be loaded from IRQ0INTNO (IRQ 0 interrupt
  1751.   number) and IRQ8INTNO.  These are public BYTE locations in DSEG.  They should
  1752.   be read only after the call to INITXLIB.
  1753.        DESQview does remap hardware interrupts; however, its interrupt handlers
  1754.   for the new locations generally transfer control to the addresses at the
  1755.   conventional vectors.  DESQview must be started with a command-line switch if
  1756.   it is to accommodate certain hardware interrupts.  In particular, the FPU
  1757.   interrupt will not function properly under DESQview unless DESQview is started
  1758.   with DV /HW:75:C.
  1759.  
  1760.  
  1761.   Detailed Specifications
  1762.  
  1763.  
  1764.   PMGETRMIV (Protected Mode - Get Real-Mode Interrupt Vector)
  1765.   Purpose:  Retrieve address of real-mode interrupt handler.
  1766.   CPU Mode:  Protected
  1767.   Registers at Call:  AL = interrupt number.
  1768.   Return Registers:  Handler address returned in CX:DX.
  1769.   Details:  The DOS routine for this purpose (INT 21H function 35H) is not
  1770.   useful because it returns a value in ES.
  1771.  
  1772.   PMSETRMIV (Protected Mode - Set Real-Mode Interrupt Vector)
  1773.   Purpose:  Set address of real-mode interrupt handler.
  1774.   CPU Mode:  Protected
  1775.   Registers at Call:  AL = interrupt number, CX:DX = address of handler.
  1776.   Return Registers:  None
  1777.   Details:
  1778.      The DOS routine for this purpose (INT 21H function 25H) is not useful
  1779.   because it requires an argument in DS.
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.                                         23
  1786.  
  1787.  
  1788.  
  1789.  
  1790.  
  1791.  
  1792.      Real-mode interrupt handlers will also be called when interrupts occur in
  1793.   protected mode provided that the protected-mode interrupt handler cascades the
  1794.   interrupt.  This is in fact the case for all interrupts.
  1795.      XLIB never disables handlers installed by this procedure.
  1796.  
  1797.   GETPMIV (Get Protected-Mode Interrupt Vector)
  1798.   Purpose:  Retrieve address of protected-mode interrupt handler from interrupt
  1799.   descriptor table.
  1800.   CPU Mode:  Real
  1801.   Registers at Call:  AL = interrupt number.
  1802.   Return Registers:  Handler address returned in CX:EDX (CX is a selector).
  1803.   Details:  This routine does not return addresses of CPU exception handlers
  1804.   under DPMI.  Use DPMI functions directly for this purpose.
  1805.  
  1806.   SETPMIV (Set Protected-Mode Interrupt Vector)
  1807.   Purpose:  Set address of protected-mode interrupt handler in interrupt
  1808.   descriptor table.
  1809.   CPU Mode:  Real
  1810.   Registers at Call:  AL = interrupt number.  Handler address in CX:EDX (CX is a
  1811.   selector).
  1812.   Return Registers:  EAX = 0 if successful.  EAX = error code if unsuccessful.
  1813.   AX = XLIB error code.  If DPMI is installed then the high word of EAX will
  1814.   contain a DPMI 1.0 error code (if provided by host).
  1815.   Details:
  1816.      XLIB never disables handlers installed by this procedure.
  1817.      Protected-mode interrupt handlers never receive interrupts occurring in
  1818.   real mode unless DPMI is active.  Under DPMI all hardware interrupts (IRQs 0-
  1819.   15) and software interrupts 1CH, 23H, and 24H are deflected from real mode to
  1820.   the installed protected-mode handler.  The protected-mode handler therefore
  1821.   receives control of the interrupt first.  It may cascade the interrupt if so
  1822.   desired, in which event, the real-mode handler receives the interrupt next. If
  1823.   no protected-mode handler has been installed, then DPMI generally deflects the
  1824.   interrupt to the real-mode handler.
  1825.      All protected-mode handlers will receive control with interrupts disabled
  1826.   unless DPMI is installed.  Under DPMI, protected-mode software interrupts
  1827.   apart from 0-7 do not alter the state of the virtual interrupt flag.
  1828.      Protected-mode handlers under DPMI for hardware interrupts and software
  1829.   interrupts 0-7 should execute STI before IRET to ensure that the virtual
  1830.   interrupt flag is enabled.
  1831.      If multiple DPMI clients are running in the same virtual machine, then the
  1832.   primary client (most recently installed client) always receives hardware
  1833.   interrupts.
  1834.      If DPMI .9 is installed, then protected-mode interrupt vectors should be
  1835.   reset to original values before termination.  Such action is not required for
  1836.   DPMI 1.0.
  1837.      This routine should not be used to install CPU exception handlers under
  1838.   DPMI.  DPMI functions should be used for this purpose.
  1839.  
  1840.   PMGETPMIV (Protected Mode - Get Protected-Mode Interrupt Vector)
  1841.   Purpose:  Retrieve address of protected-mode interrupt handler from interrupt
  1842.   descriptor table.
  1843.   CPU Mode:  Protected
  1844.   Details:  This routine is the protected-mode version of GETPMIV.  See GETPMIV
  1845.   for specifications.
  1846.  
  1847.  
  1848.  
  1849.                                         24
  1850.  
  1851.  
  1852.  
  1853.  
  1854.  
  1855.  
  1856.   PMSETPMIV (Protected Mode - Set Protected-Mode Interrupt Vector)
  1857.   Purpose:  Set address of protected-mode interrupt handler in interrupt
  1858.   descriptor table.
  1859.   CPU Mode:  Protected
  1860.   Details:  This routine is the protected-mode version of SETPMIV.  See SETPMIV
  1861.   for specifications.
  1862.  
  1863.   DEFLECTPM (Deflect to Protected-Mode)
  1864.   Purpose:  Call a protected-mode interrupt handler.
  1865.   CPU Mode:  Real
  1866.   Registers at Call:  SS:ESP = interrupt number (2 bytes)
  1867.   Return Registers:  Segment registers are preserved through the call.  The
  1868.   interrupt flag is also preserved through the call.  All other registers are
  1869.   returned at values existing as of the protected-mode IRET instruction.
  1870.   Details:
  1871.      The protected-mode handler will always receive interrupts disabled.  It may
  1872.   enable interrupts if desired; however, once control is returned to DEFLECTPM,
  1873.   the interrupt flag will be reset to its original value.
  1874.      This procedure can be used only under VCPI and XLIB mode switching.  It
  1875.   returns with no action under DPMI.  The routine is intended to simulate DPMI
  1876.   treatment of hardware interrupts, INT 1CH, INT 23H, and INT24H.  The routine
  1877.   may be called from a real-mode interrupt handler to deflect the interrupt to
  1878.   the protected-mode handler.
  1879.      The protected-mode handler should not cascade the interrupt; otherwise, an
  1880.   infinite loop will result.
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886.  
  1887.  
  1888.  
  1889.  
  1890.  
  1891.  
  1892.  
  1893.  
  1894.  
  1895.  
  1896.  
  1897.  
  1898.  
  1899.  
  1900.  
  1901.  
  1902.  
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.                                         25
  1914.  
  1915.  
  1916.  
  1917.  
  1918.  
  1919.  
  1920.                                7. Memory Management
  1921.  
  1922.  
  1923.        XLIB supplies memory management procedures for both real and protected
  1924.   modes.  These procedures are configured at initialization to work with the
  1925.   currently resident memory management interfaces.
  1926.        Conventional memory may be allocated and released in real mode through
  1927.   DOS in usual fashion (INT 21H functions 48H and 49H).  However, DOS functions
  1928.   may not work properly in protected mode.  Therefore, use the XLIB routines
  1929.   PMGETDOSMEM and PMFREEDOSMEM for such requests.  PMFREEDOSMEM can also be used
  1930.   to find the amount of available DOS memory.
  1931.        The real-mode extended memory management procedures are GETMEM, FREEMEM,
  1932.   and RESETMEM.  GETMEM is used to allocate a block of extended memory.  FREEMEM
  1933.   may then be used to release the block.  RESETMEM releases all previously
  1934.   allocated blocks at once.  GETMEM may also be used to find the amount of
  1935.   available extended memory.
  1936.        The protected-mode memory management procedures are PMGETMEM, PMFREEMEM,
  1937.   and PMRESETMEM.  These procedures function exactly as the corresponding real-
  1938.   mode procedures:  GETMEM, FREEMEM, and RESETMEM.
  1939.        XLIB will seek extended memory through XMS only if it is present and if
  1940.   both DPMI and VCPI are absent.  If either protected-mode interface is present,
  1941.   then all extended memory will be allocated through the configured interface.
  1942.        XLIB will not use XMS to allocate memory from the high memory area (HMA)
  1943.   or from upper memory blocks (UMBs).  XLIB will however allocate from the HMA
  1944.   when it has full responsibility for extended memory management (DPMI, VCPI,
  1945.   and XMS are all absent).  XLIB never issues calls under EMS (apart from calls
  1946.   to VCPI).
  1947.        Under DPMI and VCPI, the CPU will typically be operating in page mode.
  1948.   Under this mode of operation, memory may be remapped such that logical
  1949.   addresses are not equal to physical addresses.  Addresses specified in the
  1950.   instruction code are logical addresses.  The physical addresses are the
  1951.   locations in memory which are actually accessed.  Typically, a programmer need
  1952.   not be concerned with the difference between these two types of addresses.
  1953.   However, the difference must be recognized when working with input/output
  1954.   devices which map to certain physical location in memory.  XLIB includes
  1955.   routines called MAPIO and PMMAPIO which assign logical addresses to specified
  1956.   physical addresses.  The physical addresses can then be accessed via the
  1957.   assigned logical addresses.
  1958.        If DPMI 1.0 is installed, then XLIB can also manage uncommitted memory.
  1959.   Uncommitted memory is a logical address space having no physical memory
  1960.   backing it.  Addresses within the space become committed only after they have
  1961.   been accessed through a read or write operation.  Uncommitted memory can
  1962.   become useful when a program needs to manage an array of uncertain size.  The
  1963.   program would need the ability to handle the array when it is large, but would
  1964.   not wish to consume physical memory by dimensioning a large array when only a
  1965.   small array was needed.  Such objectives can be achieved by fixing the array
  1966.   over uncommitted memory.
  1967.        The real-mode routines for managing uncommitted memory are GETUMEM and
  1968.   UNCOMMITMEM.  GETUMEM allocates an uncommitted address space.  As explained
  1969.   above, the space becomes committed when accessed.  The space or a portion
  1970.   thereof may be returned to uncommitted state with UNCOMMITMEM.  These
  1971.   procedures will return error codes if DPMI 1.0 is not installed.
  1972.  
  1973.  
  1974.  
  1975.  
  1976.  
  1977.                                         26
  1978.  
  1979.  
  1980.  
  1981.  
  1982.  
  1983.  
  1984.        The protected-mode versions of GETUMEM and UNCOMMITMEM are PMGETUMEM and
  1985.   PMUNCOMMITMEM.  These procedures function exactly as the corresponding real-
  1986.   mode procedures.
  1987.  
  1988.  
  1989.   Detailed Specifications
  1990.  
  1991.  
  1992.   PMGETDOSMEM (Protected Mode - Get DOS Memory)
  1993.   Purpose:  Allocate DOS memory block.
  1994.   CPU Mode:  Protected
  1995.   Registers at Call:  EAX = desired size of block in bytes.
  1996.   Return Registers:
  1997.      EAX = 0 if successful.  A block handle is returned in EBX.  The number of
  1998.   allocated bytes is returned in ECX.  The linear address of allocated block is
  1999.   returned in EDX.
  2000.      EAX = error code if unsuccessful.  AX = XLIB error code.  The high word of
  2001.   EAX (EAH) will be set to a DOS error code.  If DPMI is active, then EAH will
  2002.   be a DPMI error code (codes are supplied by DPMI .9 and up).
  2003.   Details:
  2004.      The block will always be paragraph aligned and will have size equal to an
  2005.   integer multiple of 16.
  2006.      The location in free memory from which the block is allocated will depend
  2007.   upon the allocation strategy in force as of call (see INT 21H function 58H).
  2008.      Call with EAX = 0 to get largest available DOS memory block (not total free
  2009.   memory) in ECX (EAX, EBX, and EDX are preserved).
  2010.      If DPMI is active, then the handle is actually a selector with base address
  2011.   set to the linear address of the block.  If DPMI is not active, then the
  2012.   handle will be the segment of the block.
  2013.      In real mode, DOS memory may be allocated directly from DOS (INT 21H
  2014.   function 48H); however, this call will likely fail under DPMI protected mode.
  2015.  
  2016.   PMFREEDOSMEM (Protected Mode - Free DOS Memory)
  2017.   Purpose:  Release previously allocated DOS memory block.
  2018.   CPU Mode:  Protected
  2019.   Registers at Call:  EAX = block handle.
  2020.   Return Registers:  EAX = 0 if successful; otherwise, EAX = error code.  AX =
  2021.   XLIB error.  The high word of EAX (EAH) will be a DOS error code.  If DPMI is
  2022.   active, then EAH will equal a DPMI error code (codes are supplied by DPMI .9
  2023.   and up).
  2024.   Details:  In real mode, DOS memory may be released directly by DOS (INT 21H
  2025.   function 49H); however, this call will likely fail under DPMI protected mode.
  2026.  
  2027.   GETMEM (Get Memory)
  2028.   Purpose:  Allocate extended memory block.
  2029.   CPU Mode:  Real
  2030.   Registers at Call:  EAX = desired size of block in bytes.
  2031.   Return Registers:
  2032.      EAX = 0 if successful.  A block handle is returned in EBX.  The number of
  2033.   allocated bytes is returned in ECX.  The logical address of allocated block is
  2034.   returned in EDX.
  2035.      EAX = error code if unsuccessful.  AX = XLIB error code.  If DPMI is
  2036.   active, then the high word of EAX (EAH) will be a DPMI 1.0 error code (if
  2037.   provided by host).  If XMS is active, then EAH = XMS error code.
  2038.  
  2039.  
  2040.  
  2041.                                         27
  2042.  
  2043.  
  2044.  
  2045.  
  2046.  
  2047.  
  2048.   Details:
  2049.      The page size for extended memory allocations is contained in PAGESIZE.
  2050.   PAGESIZE is a DWORD in DSEG and should be read after initialization.  The
  2051.   blocks will have addresses that are PAGESIZE aligned and will have sizes equal
  2052.   to an integer multiple of PAGESIZE.  PAGESIZE will equal:  1024 for XMS, 4096
  2053.   for VCPI, 4096 for most DPMI hosts, and 16 in the absence of a memory manager.
  2054.      If XMS is present in conjunction with either DPMI or VCPI, no extended
  2055.   memory will be requested through XMS.  All extended memory will be requested
  2056.   through the active protected-mode interface.
  2057.      XMS is never used to allocate from the HMA or from UMBs.  XLIB will however
  2058.   allocate from the HMA in the absence of a memory management interface.
  2059.      Call with EAX = 0 to get largest available extended memory block (not total
  2060.   free memory) in ECX (EBX and EDX are preserved).  This call can also return
  2061.   with an error condition in EAX.
  2062.      A total of 16 blocks may be allocated.  Blocks allocated with GETUMEM (see
  2063.   below) also count toward this total.  If more blocks are needed, then the
  2064.   programmer should allocate one large block and then apportion it.
  2065.  
  2066.   FREEMEM (Free Memory)
  2067.   Purpose:  Release previously allocated extended memory block.
  2068.   CPU Mode:  Real
  2069.   Registers at Call:  EAX = block handle.
  2070.   Return Registers:  EAX = 0 if successful; otherwise, EAX = error code.  AX =
  2071.   XLIB error code.  If DPMI is active, then the high word of EAX (EAH) will be a
  2072.   DPMI 1.0 error code (if provided by host).  If XMS is active, then EAH = XMS
  2073.   error code.
  2074.   Details:  FREEMEM does not release page tables allocated under VCPI.  Call
  2075.   RESETMEM for this purpose.
  2076.  
  2077.   RESETMEM (Reset Memory)
  2078.   Purpose:  Release all previously allocated extended memory.
  2079.   CPU Mode:  Real
  2080.   Registers at Call:  None
  2081.   Return Registers:  EAX = 0 if successful; otherwise, EAX = error code.  AX =
  2082.   XLIB error code.  If DPMI is active, then the high word of EAX (EAH) will be a
  2083.   DPMI 1.0 error code (if provided by host).  If XMS is active, then EAH = XMS
  2084.   error code.
  2085.   Details:
  2086.      GETMEM will automatically allocate page tables as needed under VCPI.
  2087.   RESETMEM will release such tables.
  2088.      If DPMI is not installed, then RESETMEM will be called upon execution of
  2089.   INT 21H function 4C (DOS termination).  DPMI hosts reset extended memory
  2090.   automatically.
  2091.  
  2092.   PMGETMEM  (Protected Mode - Get Memory)
  2093.   Purpose:  Allocate extended memory block.
  2094.   CPU Mode:  Protected
  2095.   Details:  This routine is the protected-mode version of GETMEM.  See GETMEM
  2096.   for specifications.
  2097.  
  2098.  
  2099.  
  2100.  
  2101.  
  2102.  
  2103.  
  2104.  
  2105.                                         28
  2106.  
  2107.  
  2108.  
  2109.  
  2110.  
  2111.  
  2112.   PMFREEMEM  (Protected Mode - Free Memory)
  2113.   Purpose:  Free previously allocated extended memory block.
  2114.   CPU Mode:  Protected
  2115.   Details:  This routine is the protected-mode version of FREEMEM.  See FREEMEM
  2116.   for specifications.
  2117.  
  2118.   PMRESETMEM (Protected Mode - Reset Memory)
  2119.   Purpose:  Free all previously allocated extended memory.
  2120.   CPU Mode:  Protected
  2121.   Details:  This routine is the protected-mode version of RESETMEM.  See
  2122.   RESETMEM for specifications.
  2123.  
  2124.   MAPIO (Map Input/Output Device)
  2125.   Purpose:  Create a logical address mapping for an input/output device which
  2126.   maps to a fixed physical memory address.
  2127.   CPU Mode:  Real
  2128.   Registers at Call:  EDX = first physical address to be mapped.  EAX = size of
  2129.   physical address block.
  2130.   Return Registers:
  2131.      EAX = 0 if successful, in which event, EDX = the logical address for
  2132.   accessing the physical memory.
  2133.      EAX = error code if unsuccessful.  AX = XLIB error code.  If DPMI is
  2134.   active, then the high word of EAX (EAH) will be a DPMI 1.0 error code (if
  2135.   provided by host).  If XMS is active, then EAH = XMS error code.
  2136.   Details:
  2137.      DPMI will not allow mapping of physical addresses within the first
  2138.   megabyte; however, such mappings are allowed under other configurations.
  2139.      Logical addresses will always equal physical addresses in the absence of
  2140.   VCPI and DPMI because the processor will not be operating in page mode.  In
  2141.   such cases, MAPIO simply performs validity checks on EDX and EAX.
  2142.      MAPIO will automatically allocate page tables as needed under VCPI.
  2143.   RESETMEM will release such tables.
  2144.      Memory-mapped input/output devices are not typically mapped within the
  2145.   range of available memory since this would leave the possibility of confusing
  2146.   such addresses with ordinary memory.  Instead, such devices are mapped beyond
  2147.   the highest address that would otherwise be available.
  2148.  
  2149.   PMMAPIO (Protected Mode - Map Input/Output Device)
  2150.   Purpose:  Create a logical address mapping for an input/output device which
  2151.   maps to a fixed physical memory address.
  2152.   CPU Mode:  Protected
  2153.   Details:  This routine is the protected-mode version of MAPIO.  See MAPIO for
  2154.   specifications.
  2155.  
  2156.   GETUMEM (Get Uncommitted Memory)
  2157.   Purpose:  Allocate uncommitted extended memory block.
  2158.   CPU Mode:  Real
  2159.   Registers at Call:  EAX = desired size of block in bytes.
  2160.   Return Registers:
  2161.      EAX = 0 if successful.  A block handle is returned in EBX.  The number of
  2162.   allocated bytes is returned in ECX.  The logical address of allocated block is
  2163.   returned in EDX.
  2164.      EAX = error code if unsuccessful.  AX = XLIB error code.  The high word of
  2165.   EAX will be a DPMI 1.0 error code.
  2166.  
  2167.  
  2168.  
  2169.                                         29
  2170.  
  2171.  
  2172.  
  2173.  
  2174.  
  2175.  
  2176.   Details:
  2177.      This procedure is available only under DPMI 1.0.  An error code will be
  2178.   returned under other configurations.
  2179.      The page size for extended memory allocations is contained in PAGESIZE.
  2180.   PAGESIZE is a DWORD in DSEG and should be read after initialization.  The
  2181.   blocks will have addresses that are PAGESIZE aligned and will have sizes equal
  2182.   to an integer multiple of PAGESIZE.  PAGESIZE will equal:  1024 for XMS, 4096
  2183.   for VCPI, 4096 for most DPMI hosts, and 16 in the absence of a memory manager.
  2184.      A page fault (exception 14) will be generated when uncommitted memory is
  2185.   first accessed.  XLIB will intercept this exception and fill the violating
  2186.   page with physical memory.  Uncommitted memory operations will therefore be
  2187.   slow upon first access.
  2188.      Use UNCOMMITMEM or PMUNCOMMITMEM to release physical memory mapped into the
  2189.   logical address space.  Use FREEMEM or PMFREEMEM to release both the logical
  2190.   address space and all physical memory committed to it.
  2191.      A total of 16 blocks may be allocated.  Allocations through GETMEM also
  2192.   contribute toward this total.  If more blocks are needed, then the programmer
  2193.   should allocate one large block and apportion it.
  2194.  
  2195.   UNCOMMITMEM (Uncommit Memory)
  2196.   Purpose:  Uncommit memory in logical address space.
  2197.   CPU Mode:  Real
  2198.   Registers at Call:  EAX = Memory block handle, EBX = offset within block for
  2199.   first page to be uncommitted.  ECX = number of bytes to uncommit.
  2200.   Return Registers:
  2201.      EAX = 0 if successful.
  2202.      EAX = error code if unsuccessful.  AX = XLIB error code.  The high word of
  2203.   EAX will be a DPMI 1.0 error code.
  2204.   Details:
  2205.      This procedure is available only under DPMI 1.0.  An error code will be
  2206.   returned under other configurations.
  2207.      The memory block handle must correspond to a block allocated with GETUMEM
  2208.   or PMGETUMEM.
  2209.      If either EBX or ECX are not PAGESIZE multiples, then they will be rounded
  2210.   down to the nearest multiple.
  2211.      The logical address space allocated to the block is not released.
  2212.   Therefore, the address space will be committed once again if accessed.  Use
  2213.   FREEMEM or PMFREEMEM to release the address space.
  2214.  
  2215.   PMGETUMEM (Protected Mode - Get Uncommitted Memory)
  2216.   Purpose:  Allocate uncommitted extended memory block.
  2217.   CPU Mode:  Protected
  2218.   Details:  This routine is the protected-mode version of GETUMEM.  See GETUMEM
  2219.   for details.
  2220.  
  2221.   PMUNCOMMITMEM (Protected Mode - Uncommit Memory)
  2222.   Purpose:  Uncommit memory in logical address space.
  2223.   CPU Mode:  Protected
  2224.   Details:  This routine is the protected-mode version of UNCOMMITMEM.  See
  2225.   UNCOMMITMEM for details.
  2226.  
  2227.  
  2228.  
  2229.  
  2230.  
  2231.  
  2232.  
  2233.                                         30
  2234.  
  2235.  
  2236.  
  2237.  
  2238.  
  2239.  
  2240.                                 8. File Management
  2241.  
  2242.  
  2243.        XLIB file management procedures are low-level routines with powerful
  2244.   capabilities.  These routines can load files to extended memory or save
  2245.   extended memory to files.  They can read and write files either sequentially
  2246.   or randomly.
  2247.        All XLIB file management routines will receive and return values in a
  2248.   contiguous block of memory called a "file control block" (not to be confused
  2249.   with DOS file control blocks).  The file control block must be located in
  2250.   conventional memory and must have the form presented in Table 5.
  2251.  
  2252.  
  2253.   Table 5:  XLIB File Control Block Structure
  2254.   _____________________________________________________________________________
  2255.   Field Name   Field Type        Field Description
  2256.   ----------   ----------        -----------------
  2257.   CONDCODE     DWORD             Condition code from file operation
  2258.   FNAME        BYTE[68]          File path and name (zero terminated string)
  2259.   FHANDLE      WORD              File handle assigned by DOS
  2260.   FPTRMODE     WORD              File pointer mode
  2261.   FPTR         DWORD             File pointer
  2262.   BLKADR       DWORD             Memory source/destination address
  2263.   BLKSIZE      DWORD             Size of transfer block in bytes
  2264.   BUFADR       DWORD             Buffer address (conventional memory address)
  2265.   BUFSIZE      WORD              Buffer size in bytes
  2266.   CONTROL      WORD              Control word
  2267.   _____________________________________________________________________________
  2268.  
  2269.  
  2270.        CONDCODE is used to return error codes.
  2271.        FNAME is a zero-terminated ASCII string defining the file path and name.
  2272.   There cannot be more than 67 characters in this string, excluding the
  2273.   termination character.
  2274.        BLKADR and BLKSIZE define the source/destination memory block for the
  2275.   transfer.  This block may be in either conventional or extended memory.
  2276.   BLKADR is a linear address.
  2277.        XLIB uses DOS to access the disk.  DOS cannot read or write to extended
  2278.   memory; consequently, a conventional memory buffer must be set up for the DOS
  2279.   transfers.  File management routines shift to protected mode to perform
  2280.   transfers between the buffer and the source/destination memory.  BUFADR and
  2281.   BUFSIZE define the conventional memory buffer.  BUFADR is a linear address.
  2282.        For fastest transfers, the memory block and the buffer should be DWORD
  2283.   aligned and should have sizes equal to an integer multiple of four.
  2284.        FPTR and FPTRMODE specify the file pointer setting to be used before
  2285.   transfers to or from the disk.  FPTRMODE specifies how FPTR is to be
  2286.   interpreted.  The following values are valid for FPTRMODE:
  2287.  
  2288.  
  2289.   FPTRMODE    FPTR Interpretation
  2290.   0           Unsigned offset from the beginning of the file
  2291.   1           Signed offset from the current file pointer
  2292.   2           Signed offset from the end of the file
  2293.   3           FPTR is ignored.  Use current file pointer (sequential mode)
  2294.  
  2295.  
  2296.  
  2297.                                         31
  2298.  
  2299.  
  2300.  
  2301.  
  2302.  
  2303.  
  2304.        CONTROL is not used in the present version of XLIB.  Set all bits in
  2305.   CONTROL to zero.
  2306.        In assembly language or C, the file control block would typically be
  2307.   defined by a structure.  In BASIC, the file control block can be defined with
  2308.   a user defined type.
  2309.        Values are transferred to and from all file routines in EAX and in the
  2310.   file control block.  All routines should be called with the linear address of
  2311.   the file control block in EAX.  All routines return with two copies of the
  2312.   error code - one in EAX and one in the condition code of the file control
  2313.   block.  A zero error code indicates successful execution.
  2314.        Since these routines perform disk operations, special precautions should
  2315.   be taken to ensure that parameters in the file control block are properly
  2316.   defined before performing calls.  In particular, one should always make sure
  2317.   that the source/destination memory block and the conventional memory buffer
  2318.   are properly defined.  A safe rule is to simply set the buffer size to zero
  2319.   because this forces XLIB to supply a buffer when opening or creating the file.
  2320.  
  2321.  
  2322.   Detailed Specifications
  2323.  
  2324.  
  2325.   XCREATE (Create File)
  2326.   Purpose:  Create and open a new file of specified name in specified directory.
  2327.   CPU Mode:  Real
  2328.   Registers at Call:  EAX = linear address of file control block.
  2329.   Control Block at Call:  FNAME = file path and name.
  2330.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2331.   occurred, then the high word of EAX will be set to the DOS error code.
  2332.   Control Block at Return:  CONDCODE = error code.  If CONDCODE = 0, then
  2333.   FHANDLE = file handle assigned by DOS.  If the procedure is called with
  2334.   BUFSIZE = 0, then XLIB will set BUFADR and BUFSIZE to its own internal buffer.
  2335.   Details:
  2336.      If the file already exists, then it will be truncated to zero length.
  2337.      The size and location of the internal buffer will depend upon how XLIB was
  2338.   initialized.  If DPMI is active, then the buffer will be slightly larger than
  2339.   2K; otherwise, the buffer will be slightly larger than 1K.  The linear address
  2340.   and size of the buffer may be obtained from FILEBUFADR (DWORD), and
  2341.   FILEBUFSIZE (WORD) in DSEG.
  2342.      Files created by this routine will be given both read and write access.
  2343.      This routine uses INT 21H function 3CH to create the file.
  2344.  
  2345.   XOPEN (Open File)
  2346.   Purpose:  Open existing file of specified name in specified directory.
  2347.   CPU Mode:  Real
  2348.   Registers at Call:  EAX = linear address of file control block.
  2349.   Control Block at Call:  FNAME = file path and name.
  2350.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2351.   occurred, then the high word of EAX will be set to the DOS error code.
  2352.   Control Block at Return:  CONDCODE = error code.  If CONDCODE = 0, then
  2353.   FHANDLE = file handle assigned by DOS.  If the procedure is called with
  2354.   BUFSIZE = 0, then XLIB will set BUFADR and BUFSIZE to its own internal buffer.
  2355.  
  2356.  
  2357.  
  2358.  
  2359.  
  2360.  
  2361.                                         32
  2362.  
  2363.  
  2364.  
  2365.  
  2366.  
  2367.  
  2368.   Details:
  2369.      The file is opened for both read and write access.
  2370.      The size and location of the internal buffer will depend upon how XLIB was
  2371.   initialized.  If DPMI is active, then the buffer will be slightly larger than
  2372.   2K; otherwise, the buffer will be slightly larger than 1K.  The linear address
  2373.   and size of the buffer may be obtained from FILEBUFADR (DWORD), and
  2374.   FILEBUFSIZE (WORD) in DSEG.
  2375.      This routine uses INT 21H function 3DH to open the file.
  2376.  
  2377.   XCLOSE (Close File)
  2378.   Purpose:  Close previously opened file.
  2379.   CPU Mode:  Real
  2380.   Registers at Call:  EAX = linear address of file control block.
  2381.   Control Block at Call:  FHANDLE = file handle.
  2382.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2383.   occurred, then the high word of EAX will be set to the DOS error code.
  2384.   Control Block at Return:  CONDCODE = error code.
  2385.   Details:  This routine uses INT 21H function 3EH to close the file.
  2386.  
  2387.   XSAVE (Save File)
  2388.   Purpose:  Create file with contents equal to specified memory block.
  2389.   CPU Mode:  Real
  2390.   Registers at Call:  EAX = linear address of file control block.
  2391.   Control Block at Call:  FNAME = file path and name.  BLKADR/BLKSIZE = address
  2392.   and size of memory block to provide file contents.  BUFADR/BUFSIZE = address
  2393.   and size of conventional memory buffer.
  2394.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2395.   occurred, then the high word of EAX will be set to the DOS error code.
  2396.   Control Block at Return:  CONDCODE = error code.
  2397.   Details:
  2398.      The file cannot already be open.  The file is both created and closed by
  2399.   this routine.
  2400.      This routine will replace any previously existing file named FNAME.
  2401.      BLKADR/BLKSIZE may define a conventional memory block provided that this
  2402.   block is not overlapped by BUFADR/BUFSIZE.
  2403.      If this routine is called with BUFSIZE = 0, then XLIB will automatically
  2404.   set BUFADR and BUFSIZE to its own internal buffer.
  2405.      This routine transfers the source memory to the file through the buffer.
  2406.   Transfers from buffer to disk are accomplished with INT 21H function 40H.
  2407.  
  2408.   XLOAD (Load File)
  2409.   Purpose:  Load file contents to specified memory block.
  2410.   CPU Mode:  Real
  2411.   Registers at Call:  EAX = linear address of file control block.
  2412.   Control Block at Call:  FNAME = file path and name.  BLKADR/BLKSIZE = address
  2413.   and size of memory block to receive file contents.  BUFADR/BUFSIZE = address
  2414.   and size of conventional memory buffer.
  2415.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2416.   occurred, then the high word of EAX will be set to the DOS error code.
  2417.   Control Block at Return:  CONDCODE = error code.  If CONDCODE = 0, then
  2418.   BLKSIZE = actual number of bytes transferred.
  2419.  
  2420.  
  2421.  
  2422.  
  2423.  
  2424.  
  2425.                                         33
  2426.  
  2427.  
  2428.  
  2429.  
  2430.  
  2431.  
  2432.   Details:
  2433.      The file cannot already be open.  The file is both opened and closed by
  2434.   this routine.
  2435.      The value of BLKSIZE as of call is interpreted as an upper limit on the
  2436.   number of bytes to transfer.  The entire file is loaded provided that it does
  2437.   not contain more than BLKSIZE bytes.
  2438.      BLKADR/BLKSIZE may define a conventional memory block provided that this
  2439.   block is not overlapped by BUFADR/BUFSIZE.
  2440.      If this routine is called with BUFSIZE = 0, then XLIB will automatically
  2441.   set BUFADR and BUFSIZE to its own internal buffer.
  2442.      This routine uses INT 21H function 3FH to transfer the disk contents to the
  2443.   buffer.  It then transfers the buffer contents to the destination memory.
  2444.  
  2445.   XWRITE (Write to File)
  2446.   Purpose:  Write specified memory block to specified location in open file.
  2447.   CPU Mode:  Real
  2448.   Registers at Call:  EAX = linear address of file control block.
  2449.   Control Block at Call:  FHANDLE = file handle.  FPTR/FPTRMODE = file pointer
  2450.   setting for beginning of transfer.  BLKADR/BLKSIZE = address and size of
  2451.   memory block to provide file contents.  BUFADR/BUFSIZE = address and size of
  2452.   conventional memory buffer.
  2453.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2454.   occurred, then the high word of EAX will be set to the DOS error code.
  2455.   Control Block at Return:  CONDCODE = error code.
  2456.   Details:
  2457.      The file must be opened with XOPEN or XCREATE before using this routine.
  2458.      BLKADR/BLKSIZE may define a conventional memory block provided that this
  2459.   block is not overlapped by BUFADR/BUFSIZE.
  2460.      This routine uses INT 21H function 42H to set the file pointer.  The source
  2461.   memory is then transferred through the buffer to disk.  Transfers from buffer
  2462.   to disk are accomplished with INT 21H function 40H.
  2463.      Sequential transfers should set FPTRMODE = 3 for fastest execution.
  2464.  
  2465.   XREAD (Read From File)
  2466.   Purpose:  Load specified memory block from specified location in open file.
  2467.   CPU Mode:  Real
  2468.   Registers at Call:  EAX = linear address of file control block.
  2469.   Control Block at Call:  FHANDLE = file handle.  FPTR/FPTRMODE = file pointer
  2470.   setting for beginning of transfer.  BLKADR/BLKSIZE = address and size of
  2471.   memory block to receive file contents.  BUFADR/BUFSIZE = address and size of
  2472.   conventional memory buffer.
  2473.   Return Registers:  EAX = error code.  AX = XLIB error code.  If a DOS error
  2474.   occurred, then the high word of EAX will be set to the DOS error code.
  2475.   Control Block at Return:  CONDCODE = error code.  If CONDCODE = 0, then
  2476.   BLKSIZE = actual number of bytes transferred.
  2477.   Details:
  2478.      The file must be opened with XOPEN or XCREATE before using this routine.
  2479.      BLKADR/BLKSIZE may define a conventional memory block provided that this
  2480.   block is not overlapped by BUFADR/BUFSIZE.
  2481.      This routine uses INT 21H function 42H to set the file pointer.  The file
  2482.   contents are then transferred to the destination memory through the buffer.
  2483.   The file contents are transferred to the buffer using INT 21H function 3FH.
  2484.      Sequential transfers should set FPTRMODE = 3 for fastest execution.
  2485.  
  2486.  
  2487.  
  2488.  
  2489.                                         34
  2490.  
  2491.  
  2492.  
  2493.  
  2494.  
  2495.  
  2496.   PMXCREATE (Protected Mode - Create File)
  2497.   Purpose:  Create and open a new file of specified name in specified directory.
  2498.   CPU Mode:  Protected
  2499.   Details:  This routine is the protected-mode version of XCREATE.  See XCREATE
  2500.   for details.
  2501.  
  2502.   PMXOPEN (Protected Mode - Open File)
  2503.   Purpose:  Open an existing file of specified name in specified directory.
  2504.   CPU Mode:  Protected
  2505.   Details:  This routine is the protected-mode version of XOPEN.  See XOPEN for
  2506.   details.
  2507.  
  2508.   PMXCLOSE (Protected Mode - Close File)
  2509.   Purpose:  Close previously opened file.
  2510.   CPU Mode:  Protected
  2511.   Details:  This routine is the protected-mode version of XCLOSE.  See XCLOSE
  2512.   for details.
  2513.  
  2514.   PMXSAVE (Protected Mode - Save File)
  2515.   Purpose:  Create file with contents equal to specified memory block.
  2516.   CPU Mode:  Protected
  2517.   Details:  This routine is the protected-mode version of XSAVE.  See XSAVE for
  2518.   details.
  2519.  
  2520.   PMXLOAD (Protected Mode - Load File)
  2521.   Purpose:  Load file contents to specified memory block.
  2522.   CPU Mode:  Protected
  2523.   Details:  This routine is the protected-mode version of XLOAD.  See XLOAD for
  2524.   details.
  2525.  
  2526.   PMXWRITE (Protected Mode - Write to File)
  2527.   Purpose:  Write specified memory block to specified location in open file.
  2528.   CPU Mode:  Protected
  2529.   Details:  This routine is the protected-mode version of XWRITE.  See XWRITE
  2530.   for details.
  2531.  
  2532.   PMXREAD (Protected Mode - Read From File)
  2533.   Purpose:  Load specified memory block from specified location in open file.
  2534.   CPU Mode:  Protected
  2535.   Details:  This routine is the protected-mode version of XREAD.  See XREAD for
  2536.   details.
  2537.  
  2538.  
  2539.  
  2540.  
  2541.  
  2542.  
  2543.  
  2544.  
  2545.  
  2546.  
  2547.  
  2548.  
  2549.  
  2550.  
  2551.  
  2552.  
  2553.                                         35
  2554.  
  2555.  
  2556.  
  2557.  
  2558.  
  2559.  
  2560.                              9. Descriptor Management
  2561.  
  2562.  
  2563.        All selectors in Table 1 up to DGROUPSEL are used by XLIB procedures;
  2564.   consequently, the corresponding descriptors should never be changed.  However,
  2565.   descriptors for the other selectors may be modified.  XLIB includes a
  2566.   procedure called SETDESC (set descriptor) to facilitate such modifications.  A
  2567.   second routine called PMSETDESC is the protected-mode version of SETDESC.
  2568.        Descriptors corresponding to the inline selectors should not be changed
  2569.   in programs which also use the inline mode-switch procedures.
  2570.        XLIB will also allow descriptors to be placed in the global descriptor
  2571.   table provided that DPMI is not being used.  XLIB has no control over the
  2572.   global descriptor table under DPMI.  The global descriptor table in XLIB
  2573.   begins at a public DWORD in DSEG called GDT.  There are 48 descriptors in this
  2574.   table.  The first 32 are either in use or are reserved by XLIB.  Descriptors
  2575.   must be placed in the table by direct writes.  The first available descriptor
  2576.   begins at DSEG offset OFFSET GDT + 100H.  The selector values are simply the
  2577.   offsets from GDT.  Hence, the selector value for the first available
  2578.   descriptor is 100H.
  2579.  
  2580.  
  2581.   Detailed Specifications
  2582.  
  2583.  
  2584.   SETDESC (Set Descriptor)
  2585.   Purpose:  Change a descriptor in the local descriptor table.
  2586.   CPU Mode:  Real
  2587.   Registers at Call:  BX = selector.  EDX:EAX = the new descriptor.
  2588.   Return Registers:  EAX = error code.  AX = XLIB error code.  If DPMI is
  2589.   installed, then the high word of EAX will equal a DPMI 1.0 error code (if
  2590.   provided by host).  EDX may be returned with some modifications to the access
  2591.   rights bits.
  2592.   Details:
  2593.      The access rights bits in EDX will be edited before installation of the
  2594.   descriptor.  In particular:  The application bit will be set to indicate an
  2595.   application segment (rather than a system segment).  Reserved bits will be
  2596.   given proper settings.  The descriptor privilege level will be set to the
  2597.   appropriate value.  If the descriptor corresponds to a code segment, then the
  2598.   descriptor will also be marked as readable and nonconforming.
  2599.      Segment registers which are loaded with the old value of the descriptor
  2600.   will not necessarily be reloaded when the descriptor is changed.
  2601.  
  2602.   PMSETDESC (Protected Mode - Set Descriptor)
  2603.   Purpose:  Change a descriptor in the local descriptor table.
  2604.   CPU Mode:  Protected
  2605.   Details:  This routine is the protected-mode version of SETDESC.  See SETDESC
  2606.   for details.
  2607.  
  2608.  
  2609.  
  2610.  
  2611.  
  2612.  
  2613.  
  2614.  
  2615.  
  2616.  
  2617.                                         36
  2618.  
  2619.  
  2620.  
  2621.  
  2622.  
  2623.  
  2624.                  10. Using XLIB in High-Level Language Libraries
  2625.  
  2626.  
  2627.        The following program illustrates the usage of XLIB in libraries called
  2628.   from Microsoft BASIC 7.0.  The library contains a protected-mode procedure
  2629.   which sums the elements in a single precision array created within BASIC.  The
  2630.   general methodology here is recommended for developing assembly language
  2631.   libraries.
  2632.        Since BASIC cannot call a 32-bit segment, a real-mode interface procedure
  2633.   must be placed in a 16-bit segment to receive the BASIC call and then transfer
  2634.   execution to 32-bit protected mode.  The interface procedure is call SUMARRAY
  2635.   while the 32-bit protected-mode procedure which actually sums the array
  2636.   elements is called SUMARRAY32.
  2637.        BASIC must pass certain arguments to the library procedures.  These
  2638.   include the array address and the number of elements to be summed.  These
  2639.   arguments could be passed on the stack; however, such approach proves awkward
  2640.   since the stack must be changed when entering protected mode.  Consequently,
  2641.   BASIC places all arguments in a contiguous block of memory called a "control
  2642.   block," and then passes only the address of the control block to the library.
  2643.   BASIC constructs the control block with a user-defined type.  The first four
  2644.   bytes of the control block are reserved for placement of an error code by the
  2645.   library procedures.
  2646.        The library also contains a real-mode function called LINADR which may be
  2647.   called by BASIC to convert segment addresses to linear addresses.
  2648.        An example of this same program for Microsoft C 7.0 is included in
  2649.   Appendix E.  An example for Borland C is included in the files EXAMP3B.C and
  2650.   EXAMP3B.ASM.
  2651.  
  2652.  
  2653.   Example 3:  Calling Protected-Mode Libraries From BASIC
  2654.   _____________________________________________________________________________
  2655.                             +++++++++++++++++++++++++
  2656.                             + ASSEMBLY CODE LIBRARY +
  2657.                             +++++++++++++++++++++++++
  2658.  
  2659.  
  2660.   ;The following library should be combined with XLIB.LIB using the Microsoft
  2661.   ;LINK and LIB utilities.  If BASIC is to be executed from the QBX environment,
  2662.   ;then a quick library must be loaded with the environment.  See BASIC
  2663.   ;documentation for instructions.
  2664.  
  2665.  
  2666.                  .MODEL         LARGE,PASCAL
  2667.                  .386P
  2668.  
  2669.                  INCLUDE        XLIB.INC
  2670.  
  2671.   CSEG           SEGMENT PARA PUBLIC USE16 'CODE'
  2672.                  ASSUME CS:CSEG, DS:DSEG
  2673.  
  2674.  
  2675.  
  2676.  
  2677.  
  2678.  
  2679.  
  2680.  
  2681.                                         37
  2682.  
  2683.  
  2684.  
  2685.  
  2686.  
  2687.  
  2688.   ;Function to calculate linear address from segment address on stack.
  2689.   ;Returns linear address in EAX and DX:AX.
  2690.   LINADR         PROC FAR PUBLIC,
  2691.                  SEGADR:DWORD                  ;Segment address of variable
  2692.                  XOR            EAX,EAX        ;Clear high words
  2693.                  XOR            EDX,EDX
  2694.                  MOV            AX,WORD PTR SEGADR[2]
  2695.                  MOV            DX,WORD PTR SEGADR[0]
  2696.                  SHL            EAX,4          ;Calculate linear address
  2697.                  ADD            EAX,EDX
  2698.                  MOV            EDX,EAX        ;Return linear address in DX:AX
  2699.                  SHR            EDX,16
  2700.                  RET
  2701.   LINADR         ENDP
  2702.  
  2703.   ;Structure defining control block for SUMARRAY.
  2704.   ARRAYDATA      STRUCT
  2705.     CONDCODE     DWORD          0              ;Condition code
  2706.     N            DWORD          0              ;Number of elements to sum
  2707.     ADDRESS      DWORD          0              ;Address of first element
  2708.     SUM          DWORD          0              ;Sum of array elements
  2709.   ARRAYDATA      ENDS
  2710.  
  2711.   ;Real-mode interface to SUMARRAY32.  Segment address of control block having
  2712.   ;structure ARRAYDATA should be on the stack.
  2713.   SUMARRAY       PROC FAR PUBLIC,
  2714.                  CBSEGADR:DWORD                ;Control block segment address
  2715.                  MOV            EAX,CBSEGADR   ;Will convert to linear address
  2716.                  PUSH           EAX
  2717.                  CALL           LINADR         ;Will use linear address in EAX
  2718.                  PUSHD          OFFSET SUMARRAY32
  2719.                  CALL           ENTERPM        ;Execute SUMARRAY32 in protected
  2720.                  RET
  2721.   SUMARRAY       ENDP
  2722.  
  2723.   CSEG           ENDS
  2724.  
  2725.   TSEG           SEGMENT PARA PUBLIC USE32 'CODE'
  2726.                  ASSUME CS:TSEG, SS:TSEG, DS:TSEG, ES:TSEG, FS:DSEG, GS:DGROUP
  2727.  
  2728.  
  2729.  
  2730.  
  2731.  
  2732.  
  2733.  
  2734.  
  2735.  
  2736.  
  2737.  
  2738.  
  2739.  
  2740.  
  2741.  
  2742.  
  2743.  
  2744.  
  2745.                                         38
  2746.  
  2747.  
  2748.  
  2749.  
  2750.  
  2751.  
  2752.   ;Sum the elements of a single precision array.  Array parameters are stored
  2753.   ;in a control block having structure of ARRAYDATA.  The linear address of the
  2754.   ;control block is contained in EAX.  An error code of -1 is returned in the
  2755.   ;condition code of the control block if the number of array elements is zero.
  2756.   ;Observe that this routine will be called with DS = FLATDSEL (flat-model data
  2757.   ;descriptor).
  2758.   SUMARRAY32     PROC NEAR
  2759.                  MOV            EDX,ARRAYDATA.ADDRESS[EAX]    ;Get array address
  2760.                  MOV            ESI,ARRAYDATA.N[EAX]          ;Get N
  2761.                  SUB            ESI,1
  2762.                  JB             NODATA                        ;Error:  N = 0
  2763.                  FLDZ                                         ;Initialize sum
  2764.   SUMLOOP:       FADD           DWORD PTR [EDX+4*ESI]
  2765.                  SUB            ESI,1
  2766.                  JAE            SUMLOOP
  2767.                  FSTP           ARRAYDATA.SUM[EAX]            ;Save sum
  2768.                  RET
  2769.   NODATA:        MOV            ARRAYDATA.CONDCODE[EAX],-1    ;Record error code
  2770.                  RET
  2771.   SUMARRAY32     ENDP
  2772.  
  2773.   TSEG           ENDS
  2774.                  END
  2775.  
  2776.  
  2777.                               +++++++++++++++++++++
  2778.                               + BASIC MAIN MODULE +
  2779.                               +++++++++++++++++++++
  2780.  
  2781.  
  2782.   'The following Microsoft BASIC 7.0 program should be linked with the above
  2783.   'library.  The BASIC program first initializes XLIB.  Next, it creates a
  2784.   'single precision array.  A control block for SUMARRAY is then constructed
  2785.   'and the call to SUMARRAY is executed.  Finally, the condition code in the
  2786.   'control block is inspected and results are printed.
  2787.  
  2788.   DEFINT A-Z
  2789.  
  2790.   'Declare XLIB procedures
  2791.   DECLARE FUNCTION XLIBMEMREQ& ()
  2792.   DECLARE FUNCTION INITXLIB& ()
  2793.   DECLARE FUNCTION XLIBCONFIG% ()
  2794.  
  2795.   'Declare procedures in the library linked with XLIB
  2796.   DECLARE FUNCTION LINADR& (SEG VARIABLE AS ANY)
  2797.   DECLARE SUB SUMARRAY (SEG VARIABLE AS ANY)
  2798.  
  2799.   'Structure for the control block
  2800.   TYPE ARRAYDATA
  2801.     CONDCODE AS LONG      'Location to receive any error codes
  2802.     N AS LONG             'Number of elements to be summed
  2803.     ADDRESS AS LONG       'Linear address of the array
  2804.     SUM AS SINGLE         'Location for array sum
  2805.   END TYPE
  2806.  
  2807.  
  2808.  
  2809.                                         39
  2810.  
  2811.  
  2812.  
  2813.  
  2814.  
  2815.  
  2816.  
  2817.   'Check XLIBCONFIG to see if XLIB has already been initialized.  If not then
  2818.   'call XLIBMEMREQ to find amount of conventional memory needed by XLIB and
  2819.   'release at least this amount with the BASIC SETMEM function.  XLIBMEMREQ
  2820.   'returns with sign bit of DX set if an error occurred.  The error is then
  2821.   'identified by AX.  XLIB will not be terminated upon completion of this
  2822.   'program in the Microsoft QBX environment; therefore, initialization is
  2823.   'required only once within the environment.
  2824.   IF XLIBCONFIG = 0 THEN
  2825.     TEMP& = XLIBMEMREQ
  2826.     IF TEMP& >= 0& THEN
  2827.       IF TEMP& > 0 THEN TEMP& = SETMEM(-TEMP& - 16&)
  2828.       TEMP& = INITXLIB                 'INITXLIB error code returned in TEMP&
  2829.     ELSE
  2830.       TEMP& = TEMP& AND &H7FFFFFFF     'Mask sign bit to leave error code only
  2831.     END IF
  2832.     IF TEMP& THEN
  2833.       PRINT "Library initialization error:  "; HEX$(TEMP&)
  2834.       END
  2835.     END IF
  2836.   END IF
  2837.  
  2838.   DIM A(100) AS SINGLE
  2839.   DIM AD AS ARRAYDATA
  2840.  
  2841.   FOR I = 0 TO 100            'Assign numbers to array
  2842.     A(I) = I
  2843.   NEXT I
  2844.  
  2845.   AD.CONDCODE = 0&            'Clear the error code
  2846.   AD.N = 50&                  'Sum first 50 elements
  2847.   AD.ADDRESS = LINADR(A(0))   'Calculate and record linear address of A(0)
  2848.  
  2849.   CALL SUMARRAY(AD)
  2850.  
  2851.   IF AD.CONDCODE THEN
  2852.     PRINT "Error: ";HEX$(AD.CONDCODE)
  2853.   ELSE
  2854.     PRINT "Sum: ";AD.SUM      'Should equal 1225
  2855.   ENDIF
  2856.  
  2857.   END
  2858.   _____________________________________________________________________________
  2859.  
  2860.  
  2861.  
  2862.  
  2863.  
  2864.  
  2865.  
  2866.  
  2867.  
  2868.  
  2869.  
  2870.  
  2871.  
  2872.  
  2873.                                         40
  2874.  
  2875.  
  2876.  
  2877.  
  2878.  
  2879.  
  2880.                11. Using XLIBE for Debugging and Exception Trapping
  2881.  
  2882.  
  2883.        XLIBE.LIB contains all of the functions of XLIB.LIB plus other functions
  2884.   designed for debugging and exception trapping.  XLIBE.LIB consumes more memory
  2885.   than XLIB.LIB; consequently, the programmer may wish to use the former for
  2886.   program development and the latter for release versions.  The same header and
  2887.   include files are used for both libraries.
  2888.        Typically, a VCPI server or a DPMI host will be accompanied with
  2889.   exception handlers.  However, because such handlers do not have specific
  2890.   knowledge of the programs they will be serving, they typically do a relatively
  2891.   poor job of restoring machine state after an exception occurs.  As a
  2892.   consequence, reboot is often necessary.  Also, such handlers generally do a
  2893.   poor job of reporting the machine state as of the exception; consequently,
  2894.   they are of limited usefulness toward debugging programs.
  2895.        XLIBE.LIB contains protected-mode handlers for all CPU exceptions.  These
  2896.   handlers will generally be able to perform complete cleanup after an exception
  2897.   occurs thereby eliminating the need for reboot.  The state of the machine as
  2898.   of the exception is thoroughly reported; therefore, the programmer should be
  2899.   able to quickly identify the source of the exception.
  2900.        If DPMI 1.0 is being used, then XLIBE can also trap exceptions occurring
  2901.   in real mode.  This ability makes XLIBE useful even to programmers who would
  2902.   otherwise be writing exclusively real-mode code.
  2903.        All of the additional features of XLIBE are activated by default.  Once
  2904.   the call to INITXLIB has been successfully executed, protected-mode exception
  2905.   trapping will be enabled, and real-mode exception trapping will be enabled
  2906.   provided that DPMI 1.0 is installed.  The default behavior of XLIBE can
  2907.   however be modified by IFLAGS, as described below.
  2908.        Two CPU exceptions are specifically designed for debugging.  These are
  2909.   exception #1 and exception #3.  Exception #1 is used for debug data
  2910.   breakpoints.  This exception is generated with any attempt to access
  2911.   predefined addresses in either data or code.  As many as four data breakpoint
  2912.   addresses may be defined with use of XLIBE procedures.  Exception #3 is
  2913.   generated by the INT 3 instruction.  This instruction may be inserted in the
  2914.   code at any point where the programmer wishes to inspect the processor state.
  2915.   The XLIBE handlers for both exceptions are designed to allow the programmer
  2916.   the option of resuming execution after the exceptions are reported.
  2917.        One of the notorious flaws in the IBM AT architecture is the manner in
  2918.   which hardware interrupts are programmed.  Hardware interrupt requests (IRQs)
  2919.   0-7 are assigned to interrupt vectors 8-15.  Unfortunately, these same
  2920.   interrupt vectors are used for CPU exceptions.  Consequently, when an
  2921.   interrupt occurs through one of these vectors, it is sometimes difficult to
  2922.   determine if the interrupt was generated by external hardware or by the CPU.
  2923.   For example, an INT 8 could be generated either by the system timer or by a
  2924.   double fault exception.  The INT 8 handler should, if possible, make a
  2925.   determination of the source of the interrupt before servicing it.  However, an
  2926.   easier and more reliable solution is to correct the problem at its root by
  2927.   remapping hardware interrupts to different vectors.  The approach taken by
  2928.   XLIBE will depend upon the active protected-mode host/server.
  2929.        If DPMI is not installed, then the default behavior of XLIBE is to remap
  2930.   hardware interrupts during initialization.  By default, XLIBE remaps IRQs 0-8
  2931.   to vectors 50H-57H and IRQs 9-15 to vectors 58H-5FH.  These vectors may
  2932.   however be changed by the programmer.  The target vectors are contained in
  2933.   PIC1BASEINT (programmable interrupt controller #1 base interrupt) and
  2934.  
  2935.  
  2936.  
  2937.                                         41
  2938.  
  2939.  
  2940.  
  2941.  
  2942.  
  2943.  
  2944.   PIC2BASINT.  Both variables are BYTE locations in DSEG.  They should be
  2945.   changed before calling INITXLIB.  The base interrupt vectors must be evenly
  2946.   divisible by eight.
  2947.        IRQs 9-15 are traditionally assigned to vectors 70H-77H.  This mapping
  2948.   poses no problem because there is no conflict with CPU exceptions at these
  2949.   addresses.  XLIB remaps to 50H-57H simply because these addresses have been
  2950.   used in other protected-mode software (e.g. DESQview and OS/2 1.x).
  2951.        XLIBE will not attempt to remap hardware interrupts if it discovers that
  2952.   the mappings have already been changed from their conventional locations.
  2953.   INITXLIB terminates with an error code in such cases.
  2954.        When XLIBE remaps hardware interrupts, it also installs real-mode
  2955.   handlers at the new hardware interrupt vectors.  These handlers simply
  2956.   transfer execution to the addresses at the old vectors.  This approach ensures
  2957.   complete compatibility with any resident software which may expect
  2958.   conventional hardware interrupt mappings.  Accordingly, the programmer should
  2959.   install real-mode hardware interrupt handlers in usual fashion.  For example,
  2960.   a timer-tick interrupt handler should be installed at INT 8.  However,
  2961.   protected-mode handlers for these interrupts should be installed at the new
  2962.   vectors.  The new vectors should be read from IRQ0INTNO and IRQ8INTNO after
  2963.   calling INITXLIB.
  2964.        The approach taken under DPMI is somewhat different.  The DPMI host will
  2965.   expect conventional hardware interrupt mappings.  The host will always
  2966.   immediately receive control after interrupts.  The host will identify the
  2967.   interrupt as being a software interrupt, hardware interrupt, or CPU exception.
  2968.   It will then transfer control to the appropriate handler.  Consequently, it is
  2969.   not necessary for XLIBE to remap hardware interrupts under DPMI.  The values
  2970.   in PIC1BASEINT and PIC2BASEINT are ignored in this case.  After the call to
  2971.   INITXLIB, IRQ0INTNO will equal 08H and IRQ8INTNO will equal 70H.
  2972.        XLIBE allows a high degree of control over exception trapping behavior.
  2973.   Three bits in IFLAGS are designed for this purpose.  Bit 1 can be set to
  2974.   disable all exception trapping and remap of hardware interrupts.  XLIBE is
  2975.   functionally equivalent to XLIB when this bit is set.  Bit 2 may be set to
  2976.   disable real-mode exception trapping.  This bit is meaningful only when DPMI
  2977.   1.0 is installed and when bit 1 is clear.  Bit 3 may be set to prevent XLIBE
  2978.   from accessing the CPU debug registers.  This bit is meaningful only if bit 1
  2979.   is clear.  The programmer may wish to set this bit if a debugger is being
  2980.   used.  All of these bits are clear by default.
  2981.        The programmer may selectively install exception handlers by altering the
  2982.   bit settings in CPUINTFLAGS (CPU interrupt flags).  CPUINTFLAGS is a public
  2983.   DWORD in DSEG.  A set bit enables installation of the the corresponding
  2984.   exception handler.  The default value of CPUINTFLAGS is FFFBH.  This enables
  2985.   installation of handlers for all exceptions apart from exception #2 (non-
  2986.   maskable interrupt), exception #16 (FPU exception), and exception #17
  2987.   (alignment check).  FPU exceptions are handled in the AT architecture through
  2988.   a hardware interrupt (IRQ 13) rather than exception #16.  Alignment is seldom
  2989.   demanded in the AT architecture.
  2990.        When an exception occurs, the XLIBE exception handlers print useful
  2991.   information about the exception in a screen report.  Appendix H contains
  2992.   instructions for interpreting this information and for identification of the
  2993.   source of the exception.
  2994.  
  2995.  
  2996.  
  2997.  
  2998.  
  2999.  
  3000.  
  3001.                                         42
  3002.  
  3003.  
  3004.  
  3005.  
  3006.  
  3007.  
  3008.   Detailed Specifications
  3009.  
  3010.  
  3011.      The procedures presented in this section are contained in XLIBE.LIB but not
  3012.   in XLIB.LIB.
  3013.  
  3014.  
  3015.   SETWATCH (Set Watchpoint)
  3016.   Purpose:  Set a data breakpoint for generation of exception #1.
  3017.   CPU Mode:  Real
  3018.   Registers at Call:  EAX = linear address of breakpoint.  DL = length of
  3019.   breakpoint in bytes.  DH = type of breakpoint.  DL must equal 1, 2, or 4.
  3020.   Alternative values for DH are:  0 - execution breakpoint, 1 - write
  3021.   breakpoint, and 2 - read/write breakpoint.
  3022.   Return Registers:  EAX = error code.  AX = XLIB error code.  If DPMI is
  3023.   installed, then the high word of EAX will equal a DPMI 1.0 error code (if
  3024.   provided by host).  EBX = handle for releasing the breakpoint.
  3025.   Details:
  3026.      The linear address supplied in EAX must have alignment equal to the length
  3027.   supplied in DL.
  3028.      If an execute breakpoint is specified (DH = 0), then the length must equal
  3029.   1 (DL = 1).
  3030.      Exception #1 is generated upon access of any byte within the breakpoint
  3031.   field.
  3032.      Up to four data breakpoints may be simultaneously defined.
  3033.      Under all protected-mode configurations except DPMI .9, the handle will
  3034.   equal the number of the assigned debug breakpoint register.  The DPMI .9
  3035.   specifications have no requirements for handle values.
  3036.      The exception report will print the value of DR6 (debug status register).
  3037.   This register may be examined to determine which breakpoint generated the
  3038.   exception.  The lowest four bits contain this information.  Set bits indicate
  3039.   that the corresponding breakpoint condition is satisfied.
  3040.      The presented value for DR6 is not relevant under DPMI .9.  Under DPMI 1.0,
  3041.   the presented value is for a virtual DR6 and will not have exact
  3042.   correspondence with the actual DR6.  In particular, bits 15 and 13 (BT and BD
  3043.   bits) are undefined.  Under XLIB and VCPI mode switching, the actual DR6 is
  3044.   presented.
  3045.      If the programmer chooses to resume execution from the exception handler,
  3046.   then DR6 will be cleared before resumption.
  3047.      Breakpoints are globally enabled under XLIB and VCPI mode switching.
  3048.   Breakpoint visibility under DPMI will depend upon the host.
  3049.      Under XLIB or VCPI mode switching, exact breakpoint matching is used for
  3050.   386 processors.  This means that the reported CS:EIP points to the instruction
  3051.   which generated the exception rather than the instruction after.  Such
  3052.   behavior is always the case with 486 and Pentium processors.  Trapping
  3053.   behavior under DPMI will depend upon the host.
  3054.  
  3055.   FREEWATCH (Free Watchpoint)
  3056.   Purpose:  Release previously allocated debug data breakpoint.
  3057.   CPU Mode:  Real
  3058.   Registers at Call:  EAX = watchpoint handle.
  3059.   Return Registers:  EAX = error code.  AX = XLIB error code.  If DPMI is
  3060.   installed, then the high word of EAX will equal a DPMI 1.0 error code (if
  3061.   provided by host).
  3062.  
  3063.  
  3064.  
  3065.                                         43
  3066.  
  3067.  
  3068.  
  3069.  
  3070.  
  3071.  
  3072.   RESETWATCH (Reset Watchpoints)
  3073.   Purpose:  Release all previously allocated debug data breakpoints.
  3074.   CPU Mode:  Real
  3075.   Registers at Call:  None
  3076.   Return Registers:  EAX = error code.  AX = XLIB error code.  If DPMI is
  3077.   installed, then the high word of EAX will equal a DPMI 1.0 error code (if
  3078.   provided by host).
  3079.   Details:  Either RESETWATCH or PMRESETWATCH will be called automatically by
  3080.   XLIBE upon program termination.
  3081.  
  3082.   PMSETWATCH (Protected Mode - Set Watchpoint)
  3083.   Purpose:  Set a data breakpoint for generation of exception #1.
  3084.   CPU Mode:  Protected
  3085.   Details:  This routine is the protected-mode version of SETWATCH.  See
  3086.   SETWATCH for details.
  3087.  
  3088.   PMFREEWATCH (Protected Mode - Free Watchpoint)
  3089.   Purpose:  Release previously allocated debug data breakpoint.
  3090.   CPU Mode:  Protected
  3091.   Details:  This routine is the protected-mode version of FREEWATCH.  See
  3092.   FREEWATCH for details.
  3093.  
  3094.   PMRESETWATCH (Protected Mode - Reset Watchpoints)
  3095.   Purpose:  Release all previously allocated debug data breakpoints.
  3096.   CPU Mode:  Protected
  3097.   Details:  This routine is the protected-mode version of RESETWATCH.  See
  3098.   RESETWATCH for details.
  3099.  
  3100.  
  3101.  
  3102.  
  3103.  
  3104.  
  3105.  
  3106.  
  3107.  
  3108.  
  3109.  
  3110.  
  3111.  
  3112.  
  3113.  
  3114.  
  3115.  
  3116.  
  3117.  
  3118.  
  3119.  
  3120.  
  3121.  
  3122.  
  3123.  
  3124.  
  3125.  
  3126.  
  3127.  
  3128.  
  3129.                                         44
  3130.  
  3131.  
  3132.  
  3133.  
  3134.  
  3135.  
  3136.                    Appendix A: Description of XLIB Public Data
  3137.  
  3138.  
  3139.        The following is a summary of most public symbols for XLIB data.  These
  3140.   symbols pertain to segment DSEG except where otherwise noted.  This summary
  3141.   excludes many of the symbols presented in tables one through four.  All XLIB
  3142.   symbols conform to the PASCAL naming convention.
  3143.  
  3144.   Symbol:  CALL32PTR (CALL32 Pointer)
  3145.   Symbol Type:  DWORD
  3146.   Default Setting:  Far 16-bit protected-mode address of CALL32 procedure
  3147.   Description:  This location is a pointer to the CALL32 procedure and is
  3148.   included to facilitate intersegment calls.  The contents of the location
  3149.   should not be changed.
  3150.  
  3151.   Symbols:  CCODEPTR/CCODE (Condition Code Pointer/Condition Code)
  3152.   Symbol Types:  DWORD/DWORD
  3153.   Default Settings:  CCODEPTR = linear address of CCODE.  CCODE = 0.
  3154.   Descriptions:  XLIB hardware interrupt handlers will place flags in the
  3155.   condition code to signal the occurrence of the interrupt.  Flags are placed
  3156.   for FPU exceptions and hot key presses.  CCODEPTR initially contains the
  3157.   linear address of CCODE.  CCODEPTR may be changed by the user, but must point
  3158.   to a DWORD in conventional memory.  The user is responsible for initializing
  3159.   the condition code.
  3160.  
  3161.   Symbol:  CPUINTFLAGS (CPU Interrupt Flags)
  3162.   Symbol Type:  DWORD
  3163.   Default Setting:  FFFBH
  3164.   Description:  One can selectively enable installation of CPU exception
  3165.   handlers in XLIBE by appropriately setting the bits in CPUINTFLAGS.  A set bit
  3166.   enables the corresponding exception.  By default, installation of handlers for
  3167.   all exceptions is enabled except for nonmaskable interrupts, FPU exceptions,
  3168.   and alignment checks.  FPU exceptions are handled through IRQ 13 rather than
  3169.   the CPU.  Alignment checks are not typically made in the IBM AT architecture.
  3170.   The settings in CPUINTFLAGS have no effect on XLIB.
  3171.  
  3172.   Symbol:  CSDSEGSEL (Code Segment Copy of DSEGSEL)
  3173.   Symbol Type:  WORD
  3174.   Default Setting:  Varies with operating environment
  3175.   Description:  This is a WORD in TSEG containing the value of the DSEG
  3176.   selector.  Since XLIB selector values are not constant, they must be read from
  3177.   memory locations.  Such locations are placed in segment DSEG (see Table 1);
  3178.   however, one must know the DSEG selector to read these locations.  Therefore,
  3179.   a copy of the DSEG selector is placed in the code segment where it can always
  3180.   be found.
  3181.  
  3182.   Symbols:  CSEGVAL, TSEGVAL, DSEGVAL, DGROUPVAL (Segment Values)
  3183.   Symbol Types:  WORD
  3184.   Default Settings:  CSEG, TSEG, DSEG, DGROUP
  3185.   Descriptions:  These are memory locations initialized to the respective
  3186.   segment values.  Code in TSEG should not contain segment constants since DOS
  3187.   may not be able to handle them in relocation edits.  Read these locations to
  3188.   get segment values.  User segments should be handled the same way.  These
  3189.   locations should not be changed.
  3190.  
  3191.  
  3192.  
  3193.                                         45
  3194.  
  3195.  
  3196.  
  3197.  
  3198.  
  3199.  
  3200.   Symbols:  FILEBUFADR/FILEBUFSIZE (File Buffer Specifications)
  3201.   Symbol Types:  DWORD/WORD
  3202.   Default Settings:  Varies with operating environment
  3203.   Descriptions:  FILEBUFADR contains the linear address of the internal file
  3204.   buffer in XLIB.  FILEBUFSIZE contains the size of the buffer in bytes.  This
  3205.   buffer is used only by the file management routines.  The size and location of
  3206.   the buffer will depend upon the operating environment.  If DPMI is active,
  3207.   then the buffer will be slightly larger than 2K; it is otherwise slightly
  3208.   larger than 1K.  These location should be read only after initialization.
  3209.  
  3210.   Symbol:  FPUCW (Floating Point Unit Control Word)
  3211.   Symbol Type:  WORD
  3212.   Default Setting:  0332H
  3213.   Description:  FPUCW is optionally loaded to the FPU control word by CALLPM and
  3214.   ENTERPM.  The default sets rounding control to nearest, precision control to
  3215.   64 bits, and unmasks exceptions for overflow, zero divide, and invalid
  3216.   operations.  Exceptions for underflow, precision, and denormalized operations
  3217.   are masked, and are therefore handled internally by the FPU.  Set bit 2 of
  3218.   OFLAGS to enable FPU save/restore and load of FPUCW.
  3219.  
  3220.   Symbol:  FPUSTATE (Floating Point Unit State)
  3221.   Symbol Type:  BYTE[108]
  3222.   Default Setting:  Not applicable
  3223.   Description:  Whenever a floating point exception occurs while the XLIB FPU
  3224.   interrupt handler is enabled, the handler will store the state of the FPU in
  3225.   FPUSTATE.  The environment is always saved in 32-bit protected-mode format.
  3226.   FPUSTATE may be read by the main program to determine the exact nature of a
  3227.   floating point exception, or be reloaded to restore FPU state existing as of
  3228.   the exception.  The exception flags in the status word should be cleared
  3229.   before reloading to prevent reoccurrence of the exception.
  3230.  
  3231.   Symbol:  GDT (Global Descriptor Table)
  3232.   Symbol Type:  DWORD
  3233.   Default Setting:  Not applicable
  3234.   Description:  GDT is the first DWORD in the global descriptor table.  This
  3235.   table contains 40 descriptors.  The last sixteen are available for use.
  3236.   Descriptors must be placed in the table by direct writes.  The first available
  3237.   descriptor begins at DSEG offset OFFSET GDT + 100H.  The selector values are
  3238.   simply the offsets from GDT.  Hence, the selector value for the first
  3239.   descriptor is 100H.  The global descriptor table should not be used under
  3240.   DPMI.
  3241.  
  3242.   Symbol:  HOTKEY (Hot Key)
  3243.   Symbol Type:  WORD
  3244.   Default Setting:  0H
  3245.   Description:  HOTKEY specifies the hot key for the keyboard interrupt handler.
  3246.   The low byte of HOTKEY specifies the scan code for the key.  The upper byte
  3247.   specifies the state of the shift keys.  Bit 8 specifies SHIFT; bit 9 specifies
  3248.   CTLR, and bit 10 specifies ALT.  Set bits mean that the designated key must be
  3249.   pressed.  All other bits are ignored.  When the hot key is pressed, the XLIB
  3250.   keyboard interrupt handler will record the hot key flag at the DWORD whose
  3251.   linear address is stored at CCODEPTR.  The default setting for HOTKEY is 0.
  3252.   This setting effectively disables hot key detection since no key has a zero
  3253.   scan code.
  3254.  
  3255.  
  3256.  
  3257.                                         46
  3258.  
  3259.  
  3260.  
  3261.  
  3262.  
  3263.  
  3264.   Symbol:  IFLAGS (Initialization Flags)
  3265.   Symbol Type:  WORD
  3266.   Default Setting:  0200
  3267.   Description:  IFLAGS is used by INITXLIB to control the initialization
  3268.   process.
  3269.      Bit 0 determines DPMI/VCPI priority in the event that both interfaces are
  3270.   present.  If this bit is clear then DPMI will be installed; otherwise, VCPI
  3271.   will be installed.
  3272.      Bit 1 disables protected-mode exception trapping in XLIBE.  It also
  3273.   disables remap of hardware interrupts.  XLIBE is functionally equivalent to
  3274.   XLIB when this bit is set.  The bit does not effect XLIB.
  3275.      Bit 2 disables real-mode exception trapping in XLIBE.  This bit is
  3276.   meaningful only if DPMI 1.0 is installed and if bit 1 of IFLAGS is clear.  The
  3277.   bit does not effect XLIB.
  3278.      Bit 3 disables XLIBE usage of debug registers.  This bit is meaningful only
  3279.   if bit 1 of IFLAGS is clear.  The bit does not effect XLIB.
  3280.      The upper byte of IFLAGS determines the strategy to be used by INITXLIB if
  3281.   conventional memory is to be allocated.  The possible strategies are presented
  3282.   in Table 2.  The default causes XLIB to allocate from the highest available
  3283.   address in conventional memory.
  3284.  
  3285.   Symbol:  INLINERMPTR (INLINERM Pointer)
  3286.   Symbol Type:  DWORD
  3287.   Default Setting:  Far 16-bit protected-mode address of INLINERM procedure
  3288.   Description:  This location is a pointer to the INLINERM procedure and is
  3289.   included to facilitate intersegment calls.  The contents of the location
  3290.   should not be changed.
  3291.  
  3292.   Symbols:  IRQ0INTNO/IRQ8INTNO (IRQ X Interrupt Number)
  3293.   Symbol Types:  BYTE/BYTE
  3294.   Default Settings:  Varies with operating environment
  3295.   Descriptions:  Specifies the interrupt number assigned to IRQ X.  IRQs 0
  3296.   through 7 and IRQs 8 through 15 are assigned to contiguous interrupt numbers.
  3297.   These locations are valid only after call to INITXLIB.  Typically, IRQ 0 is
  3298.   assigned to interrupt 8, and IRQ 8 is assigned to interrupt 70H; however,
  3299.   these assignments may have been changed by system software or by XLIBE.
  3300.  
  3301.   Symbol:  OFLAGS (Operation Flags)
  3302.   Symbol Type:  WORD
  3303.   Default Setting:  Varies with operating environment
  3304.   Description:  OFLAGS controls post-initialization operation of XLIB.
  3305.      Setting bit 0 enables XLIB hardware interrupt handlers.  These handlers
  3306.   will continue to receive interrupts but will always cascade them when the bit
  3307.   is clear.  XLIB sets this bit only at calls to CALLPM and ENTERPM and then
  3308.   clears the bit upon return.  When the bit is clear, hot key detection is
  3309.   disabled, and the XLIB FPU interrupt handler is disabled.
  3310.      Setting bit 1 causes all FPU interrupts to be cascaded to the inherited
  3311.   real-mode interrupt handler.  This bit is initialized by INITXLIB.  It is set
  3312.   if no FPU is present; it is otherwise cleared.
  3313.      Setting bit 2 enables FPU save/restore in CALLPM and ENTERPM.  Setting this
  3314.   bit also causes load of FPUCW to the FPU control word.  The bit is clear by
  3315.   default.
  3316.      Setting bit 3 disables the FPU exception handler from displaying a report
  3317.   of the exception to the screen and from terminating the program.  In such
  3318.  
  3319.  
  3320.  
  3321.                                         47
  3322.  
  3323.  
  3324.  
  3325.  
  3326.  
  3327.  
  3328.   cases the main program would be expected to report and handle the exception.
  3329.   The bit is clear by default.
  3330.  
  3331.   Symbol:  PAGESIZE (Page Size)
  3332.   Symbol Type:  DWORD
  3333.   Default Setting:  Varies with operating environment
  3334.   Description:  This memory location contains the minimum unit (in bytes) for
  3335.   extended memory allocation.  PAGESIZE is initialized by INITXLIB.  It will
  3336.   contain 4096 for VCPI, 1024 for XMS, and 16 for clean configurations.  Values
  3337.   can vary under DPMI but will typically equal 4096.  Extended memory requests
  3338.   are rounded up to the nearest integer multiple of PAGESIZE.  Extended memory
  3339.   blocks will be PAGESIZE aligned.
  3340.  
  3341.   Symbols:  PIC1BASEINT/PIC2BASEINT (Programmable Interrupt Controller X Base
  3342.   Interrupt)
  3343.   Symbol Types:  BYTE/BYTE
  3344.   Default Settings:  50H/58H
  3345.   Description:  If exception trapping is enabled under XLIBE and if XLIB or VCPI
  3346.   mode switching is to be used, then hardware interrupts will be remapped during
  3347.   initialization.  PIC1BASEINT specifies the starting interrupt number for the
  3348.   master programmable interrupt controller (IRQs 0-7).  PIC2BASEINT specifies
  3349.   the starting interrupt number for the slave controller (IRQs 8-15).  These
  3350.   variables should be set to the desired values before the call to INITXLIB.
  3351.   Both interrupt numbers must be evenly divisible by eight.  These variables
  3352.   have no effect on XLIB.
  3353.  
  3354.   Symbols:  PMDS, PMES, PMFS, PMGS (Protected-Mode Segments)
  3355.   Symbol Types:  WORD
  3356.   Default Settings:  FLATDSEL, TSEGDSEL, DSEGSEL, DGROUPSEL
  3357.   Descriptions:  These memory locations are loaded to data segment registers by
  3358.   CALLPM and ENTERPM before transferring control to the protected-mode target.
  3359.   These locations are respectively loaded to DS, ES, FS, and GS.  The contents
  3360.   of these locations may be changed to any legal selectors after the call to
  3361.   INITXLIB.
  3362.  
  3363.   Symbols:  RMDS, RMES (Real-Mode Segments)
  3364.   Symbol Types:  WORD
  3365.   Default Settings:  DGROUP, DSEG
  3366.   Descriptions:  These memory locations are loaded to data segment registers by
  3367.   CALLRM before transferring control to the real-mode target.  These locations
  3368.   are respectively loaded to DS and ES.  The contents of these locations may be
  3369.   changed if desired.
  3370.  
  3371.  
  3372.  
  3373.  
  3374.  
  3375.  
  3376.  
  3377.  
  3378.  
  3379.  
  3380.  
  3381.  
  3382.  
  3383.  
  3384.  
  3385.                                         48
  3386.  
  3387.  
  3388.  
  3389.  
  3390.  
  3391.  
  3392.                            Appendix B: XLIB Error Codes
  3393.  
  3394.  
  3395.        XLIB error codes are always returned in AX.  In many cases, the high word
  3396.   of EAX will be returned with specific information about the error, such as
  3397.   XMS, DPMI, or DOS error codes.
  3398.        Although error codes are not provided in the DPMI .9 specification, many
  3399.   DPMI .9 hosts do return DPMI 1.0 error codes.  DPMI 1.0 error codes may in
  3400.   fact be DOS error codes returned to the DPMI host by DOS.  If the sign bit
  3401.   (bit 15) of the error code is clear, then the error code was issued by DOS.
  3402.        Error codes may have been changed from earlier versions of XLIB.
  3403.  
  3404.   Condition Code Flags
  3405.   01H     FPU exception
  3406.   02H     Hot key pressed
  3407.  
  3408.   General Errors
  3409.   10H     Unable to identify operating environment
  3410.   11H     DOS memory allocation failure
  3411.   12H     DOS memory release error
  3412.   13H     Failed to enable A20
  3413.   14H     Insufficient logical address space
  3414.   15H     Insufficient number of handles
  3415.   16H     Bad handle
  3416.   17H     Bad selector
  3417.   18H     Bad address
  3418.   19H     Unable to create file
  3419.   1AH     Unable to open file
  3420.   1BH     Unable to read file
  3421.   1CH     Unable to write file
  3422.   1DH     Unable to set file pointer
  3423.   1EH     Unable to close file
  3424.   1FH     Disk full
  3425.   20H     Unable to remap hardware interrupts
  3426.   21H     Bad debug data watchpoint specification
  3427.   22H     Feature unavailable
  3428.  
  3429.   Errors Occurring Under DPMI (See Appendix C for codes returned by DPMI)
  3430.   30H     Protected mode initialization failure
  3431.   31H     Descriptor allocation error
  3432.   32H     Descriptor installation error
  3433.   33H     Unable to switch protected mode interrupt vector
  3434.   34H     Insufficient extended memory error
  3435.   35H     Extended memory allocation error
  3436.   36H     Extended memory release error
  3437.   37H     DOS memory allocation error
  3438.   38H     DOS memory release error
  3439.   39H     Unable to set descriptor base address
  3440.   3AH     Physical address mapping error
  3441.   3BH     Unable to get protected-mode exception vector
  3442.   3CH     Unable to set protected-mode exception vector
  3443.   3DH     Unable to get real-mode exception vector
  3444.   3EH     Unable to set real-mode exception vector
  3445.   3FH     Unable to set debug data breakpoint
  3446.  
  3447.  
  3448.  
  3449.                                         49
  3450.  
  3451.  
  3452.  
  3453.  
  3454.  
  3455.  
  3456.   Errors Occurring Under DPMI (Continued)
  3457.   40H     Unable to release debug data breakpoint
  3458.   41H     Unable to uncommit memory
  3459.  
  3460.   Errors Occurring Under XMS (See Appendix D for codes returned by XMS)
  3461.   50H     Unable to enable A20
  3462.   51H     Unable to measure available extended memory
  3463.   52H     Insufficient extended memory error
  3464.   53H     Extended memory allocation error
  3465.   54H     Unable to lock extended memory
  3466.   55H     Unable to unlock extended memory
  3467.   56H     Extended memory release error
  3468.  
  3469.   Errors Occurring Under VCPI
  3470.   60H     Error in determining protected mode entry point
  3471.   61H     Unable to determine physical address of DOS memory page
  3472.   62H     Unable to determine hardware interrupt mappings
  3473.   63H     Insufficient extended memory error
  3474.   64H     Unable to determine number of free extended memory pages
  3475.   65H     Extended memory allocation error
  3476.   66H     Extended memory release error
  3477.   67H     Hardware interrupt remap error
  3478.  
  3479.  
  3480.  
  3481.  
  3482.  
  3483.  
  3484.  
  3485.  
  3486.  
  3487.  
  3488.  
  3489.  
  3490.  
  3491.  
  3492.  
  3493.  
  3494.  
  3495.  
  3496.  
  3497.  
  3498.  
  3499.  
  3500.  
  3501.  
  3502.  
  3503.  
  3504.  
  3505.  
  3506.  
  3507.  
  3508.  
  3509.  
  3510.  
  3511.  
  3512.  
  3513.                                         50
  3514.  
  3515.  
  3516.  
  3517.  
  3518.  
  3519.  
  3520.                          Appendix C: DPMI 1.0 Error Codes
  3521.  
  3522.  
  3523.        DPMI 1.0 error codes may in fact be DOS error codes returned to the DPMI
  3524.   host by DOS.  If the sign bit (bit 15) of the error code is clear, then the
  3525.   error code was issued by DOS.
  3526.  
  3527.  
  3528.   Number   Explanation
  3529.   8001H    Unsupported function
  3530.   8002H    Invalid state for requested operation
  3531.   8003H    System integrity would be endangered
  3532.   8004H    Deadlock situation detected by host
  3533.   8005H    Serialization request cancelled
  3534.   8010H    Resource unavailable
  3535.   8011H    Host unable to allocate descriptor
  3536.   8012H    Linear memory unavailable
  3537.   8013H    Physical memory unavailable
  3538.   8014H    Backing store unavailable
  3539.   8015H    Callback specifications cannot be allocated
  3540.   8016H    Cannot allocate handle
  3541.   8017H    Lock count limits exceeded
  3542.   8018H    Resource owned exclusively by another client
  3543.   8019H    Resource already shared by another client
  3544.   8021H    Invalid value
  3545.   8022H    Invalid selector
  3546.   8023H    Invalid handle
  3547.   8024H    Invalid callback
  3548.   8025H    Invalid linear address
  3549.   8026H    Request not supported by hardware
  3550.  
  3551.  
  3552.  
  3553.  
  3554.  
  3555.  
  3556.  
  3557.  
  3558.  
  3559.  
  3560.  
  3561.  
  3562.  
  3563.  
  3564.  
  3565.  
  3566.  
  3567.  
  3568.  
  3569.  
  3570.  
  3571.  
  3572.  
  3573.  
  3574.  
  3575.  
  3576.  
  3577.                                         51
  3578.  
  3579.  
  3580.  
  3581.  
  3582.  
  3583.  
  3584.                            Appendix D: XMS Error Codes
  3585.  
  3586.  
  3587.   Number   Explanation
  3588.   80H      Function not implemented
  3589.   81H      VDISK was detected
  3590.   82H      An A20 error occurred
  3591.   8EH      General driver error
  3592.   8FH      Unrecoverable driver error
  3593.   90H      HMA does not exist
  3594.   91H      HMA is already in use
  3595.   92H      Attempt to allocate less than HMAMIN of HMA
  3596.   93H      HMA is not allocated
  3597.   94H      A20 is still enabled
  3598.   A0H      All extended memory is allocated
  3599.   A1H      All available handles are allocated
  3600.   A2H      Invalid handle
  3601.   A3H      Source handle is invalid
  3602.   A4H      Source offset is invalid
  3603.   A5H      Destination handle is invalid
  3604.   A6H      Destination offset is invalid
  3605.   A7H      Length is invalid
  3606.   A8H      Move has an invalid overlap
  3607.   A9H      Parity error
  3608.   AAH      Block is not locked
  3609.   ABH      Block is locked
  3610.   ACH      Block lock count overflow
  3611.   ADH      Lock failed
  3612.   B0H      Only a smaller upper memory block (UMB) is available
  3613.   B1H      No UMB's are available
  3614.   B2H      UMB segment number is invalid
  3615.  
  3616.  
  3617.  
  3618.  
  3619.  
  3620.  
  3621.  
  3622.  
  3623.  
  3624.  
  3625.  
  3626.  
  3627.  
  3628.  
  3629.  
  3630.  
  3631.  
  3632.  
  3633.  
  3634.  
  3635.  
  3636.  
  3637.  
  3638.  
  3639.  
  3640.  
  3641.                                         52
  3642.  
  3643.  
  3644.  
  3645.  
  3646.  
  3647.  
  3648.                Appendix E: Calling Protected-Mode Libraries From C
  3649.  
  3650.  
  3651.        This appendix contains a C version of the BASIC program presented in
  3652.   Example 3.  Microsoft C version 7.0 is used to create a float array.  C then
  3653.   calls a protected-mode assembly language procedure in a library to sum the
  3654.   elements of the array.  The assembly language library in Example 3 will work
  3655.   here with no modification.  C calls a real-mode procedure called SUMARRAY.
  3656.   This procedure then transfers control to a 32-bit protected-mode procedure
  3657.   called SUMARRAY32.  The latter procedure performs the actual calculations.
  3658.        Parameters defining the array are placed in a contiguous block of memory
  3659.   defined by a C structure.  C passes the address of this structure to the
  3660.   library.  The first four bytes in the structure are reserved for error codes.
  3661.   SUMARRAY32 will record an error in the control block if the parameter defining
  3662.   the number of elements to be summed is zero.
  3663.        The C code is somewhat simpler than the corresponding BASIC code because
  3664.   conventional memory does not have to be released prior to calling INITXLIB.
  3665.   This follows because C does not claim all DOS memory as does BASIC.
  3666.        C is more powerful than BASIC in that it can access data under external
  3667.   symbols whereas BASIC cannot.  Access to XLIB public data is made possible in
  3668.   C by including the header file called XLIB.H.  This file makes all XLIB public
  3669.   data and public real-mode procedures visible to C.  It also contains
  3670.   declarations which adapt the PASCAL conventions of XLIB.
  3671.        A Borland version of this program and of the accompanying library may be
  3672.   found in the files EXAMP3B.C and EXAMP3B.ASM.
  3673.  
  3674.  
  3675.  
  3676.  
  3677.  
  3678.  
  3679.  
  3680.  
  3681.  
  3682.  
  3683.  
  3684.  
  3685.  
  3686.  
  3687.  
  3688.  
  3689.  
  3690.  
  3691.  
  3692.  
  3693.  
  3694.  
  3695.  
  3696.  
  3697.  
  3698.  
  3699.  
  3700.  
  3701.  
  3702.  
  3703.  
  3704.  
  3705.                                         53
  3706.  
  3707.  
  3708.  
  3709.  
  3710.  
  3711.  
  3712.   _____________________________________________________________________________
  3713.   /*The following Microsoft C 7.0 program should be linked with the assembly
  3714.   language library in Example 3.  Combine the library with XLIB.LIB using the
  3715.   Microsoft LIB utility.  The C program first initializes XLIB.  Next, it
  3716.   creates a float array.  A control block for SUMARRAY is then constructed
  3717.   and the call to SUMARRAY is executed.  Finally, the condition code in the
  3718.   control block is inspected and results are printed.*/
  3719.  
  3720.   #include <stdio.h>
  3721.   #include <xlib.h>
  3722.  
  3723.   extern unsigned long __far __pascal LINADR(void __far *ptr);
  3724.   extern void __far __pascal SUMARRAY(void __far *ptr);
  3725.  
  3726.   struct arraydata            /*Structure for passing arguments to SUMARRAY*/
  3727.   {
  3728.     unsigned long condcode;
  3729.     unsigned long n;
  3730.     unsigned long address;
  3731.     float sum;
  3732.   } ad;
  3733.  
  3734.   main()
  3735.   {
  3736.     int i;
  3737.     unsigned long temp;
  3738.     float a[101];
  3739.     temp = INITXLIB();        /*Initialize XLIB*/
  3740.     if (temp != 0)            /*See if an error occurred*/
  3741.     {
  3742.       printf("Initialization Error:  %lX\n",temp);
  3743.       return 0;
  3744.     }
  3745.  
  3746.     for(i = 0; i <= 100; i++)   /*Initialize a[]*/
  3747.       a[i] = i;
  3748.  
  3749.     ad.condcode = 0;            /*Initialize the condition code*/
  3750.     ad.n = 50;                  /*Will sum the first 50 elements in a[]*/
  3751.     ad.address = LINADR(a);     /*Compute and record linear address of a[]*/
  3752.  
  3753.     SUMARRAY(&ad);              /*Sum the array elements*/
  3754.     if (ad.condcode != 0)       /*See if an error occurred*/
  3755.     {
  3756.       printf("Error:  %lX\n",ad.condcode);
  3757.       return 0;
  3758.     }
  3759.     printf("Sum:  %f\n",ad.sum);   /*The sum should be 1225*/
  3760.   }
  3761.   _____________________________________________________________________________
  3762.  
  3763.  
  3764.  
  3765.  
  3766.  
  3767.  
  3768.  
  3769.                                         54
  3770.  
  3771.  
  3772.  
  3773.  
  3774.  
  3775.  
  3776.                           Appendix F: Technical Support
  3777.  
  3778.  
  3779.        Technical support for XLIB is provided to both registered and
  3780.   unregistered users; however, the registration fee is $70 per copy for those
  3781.   who have used technical support or who intend to use it.  The additional
  3782.   charges will be waived for those who discover bugs in the XLIB libraries.
  3783.        Before contacting TechniLib with a problem, the following steps should be
  3784.   taken:
  3785.  
  3786.   1) Ensure that your own program always checks the error codes returned by XLIB
  3787.   procedures.  These codes will likely resolve the problem.  If not, then make
  3788.   note of the code.
  3789.  
  3790.   2) Attempt to execute your program under DPMI, VCPI, and in the absence of
  3791.   both.  If the problem relates to memory management, then also attempt to
  3792.   execute your program in the presence of XMS but in the absence of DPMI and
  3793.   VCPI, then attempt to execute in the absence of all three interfaces.  It will
  3794.   generally be found that the problem occurs only under a specific interface.
  3795.   If so, then note the interface under which the problem occurs.
  3796.  
  3797.   3) If the problem occurs only under one interface, then attempt to execute
  3798.   your program under different implementations of the interface.  For example, a
  3799.   DPMI host is contained in Windows 3.1, 386MAX, QDPMI, and OS/2 2.x.  Try
  3800.   executing your program under each host and make note of the results.  Problems
  3801.   occurring only under one host are generally indicative of bugs in the host
  3802.   rather than XLIB.
  3803.  
  3804.   4) Try different options on your memory management software.
  3805.  
  3806.   5) Try different options on your compiler, assembler, and linker.  It is
  3807.   sometimes the case that code is not processed properly under some options.
  3808.  
  3809.   6) If the problem results in a processor exception, then run the program with
  3810.   one of the exception trapping libraries (e.g. XLIBE.LIB) and make note of the
  3811.   report that is presented as of the exception.
  3812.  
  3813.        Technical support is available at:
  3814.  
  3815.   Dr. David Pyles
  3816.   TechniLib Company
  3817.   P.O. Box 6818
  3818.   Jackson, Ms. 39282
  3819.   (601) 372-7433
  3820.  
  3821.   Problems may also be reported by CompuServe mail to CIS ID: 74730,167, or by
  3822.   Internet mail to davidpyles@delphi.com.
  3823.  
  3824.  
  3825.  
  3826.  
  3827.  
  3828.  
  3829.  
  3830.  
  3831.  
  3832.  
  3833.                                         55
  3834.  
  3835.  
  3836.  
  3837.  
  3838.  
  3839.  
  3840.                  Appendix G: The SWITCHPM and SWITCHRM Procedures
  3841.  
  3842.  
  3843.        SWITCHPM and SWITCHRM are the primitive mode-switch routines used by
  3844.   nearly all XLIB procedures requiring execution in both real and protected
  3845.   modes.  They are made public for users who need to perform mode switching
  3846.   tasks not otherwise provided by XLIB.  These routines do not conform to the
  3847.   general conventions followed by other XLIB procedures; consequently, they are
  3848.   presented in an appendix.
  3849.        In some cases the programmer may deem CALLPM and ENTERPM to be too slow
  3850.   for a particular mode switching task.  Both procedures consume time in storing
  3851.   register state and in making other preparations for abrupt or unpredictable
  3852.   exits from protected mode (via jumps to RETPM/EXITPM or FPU exceptions).
  3853.   SWITCHPM and SWITCHRM perform mode switches in minimum CPU time.
  3854.        The greatest limitation to CALLPM/ENTERPM is that these procedures are
  3855.   not reentrant; consequently, calls to these procedures cannot be nested.  This
  3856.   limitation could prove a problem if the programmer needed to perform a mode
  3857.   switch within a real-mode interrupt handler.  If the interrupt originated in
  3858.   protected mode, then CALLPM/ENTERPM could not be used to perform the mode
  3859.   switch.  Since interrupt handlers generally should not make assumptions about
  3860.   machine state, CALLPM/ENTERPM generally should not be used within such
  3861.   handlers.  Use SWITCHPM and SWITCHRM instead.
  3862.        A less likely situation occurs where the programmer first enters
  3863.   protected mode via CALLPM/ENTERPM then executes real-mode code with CALLRM.
  3864.   The real-mode code could not then switch to protected mode with CALLPM/ENTERPM
  3865.   since this would be nesting the procedures.
  3866.        Both SWITCHPM and SWITCHRM are near procedures in CSEG; therefore, they
  3867.   must be called from this segment.  SWITCHPM returns to the caller in 16-bit
  3868.   protected mode.  SWITCHRM returns to the caller in real mode.  Both procedures
  3869.   must be called with a stack in DSEG.
  3870.        SWITCHPM returns with CS = CSEGSEL and with all other segments equal to
  3871.   DSEGSEL.  All other registers, including the status flags, are preserved.
  3872.        SWITCHRM returns with CS = CSEG and with SS, DS, and ES set to DSEG.  FS
  3873.   and GS are undefined.  All other registers, including the status flags, are
  3874.   preserved.
  3875.        Each interrupt handler using SWITCHPM/SWITCHRM should have its own unique
  3876.   stack in DSEG in the event that nested interrupts occurred.
  3877.        After switching to 16-bit protected mode with SWITCHPM, one can transfer
  3878.   execution to a 32-bit segment with a far call.
  3879.        An example using the techniques discussed above is the MOVMEM function in
  3880.   the file EASYX.ASM.  This function is not an interrupt handler; however, it is
  3881.   designed to be called from such handlers and must therefore abide by the same
  3882.   principles.
  3883.  
  3884.  
  3885.  
  3886.  
  3887.  
  3888.  
  3889.  
  3890.  
  3891.  
  3892.  
  3893.  
  3894.  
  3895.  
  3896.  
  3897.                                         56
  3898.  
  3899.  
  3900.  
  3901.  
  3902.  
  3903.  
  3904.                               Appendix H: Debugging
  3905.  
  3906.  
  3907.        DOS-extended programs require exceptionally powerful debuggers since
  3908.   capability is needed for both real and protected-mode code.  One of the best
  3909.   debuggers having such capabilities is 386SWAT.  See SWAT.DOC in the XLIB
  3910.   archive for information concerning this debugger.
  3911.        Unfortunately, neither Microsoft's CodeView nor Borland's Turbo Debugger
  3912.   are fully capable of debugging DOS-extended programs.  The real-mode areas of
  3913.   such programs can be debugged with these debuggers provided that no attempts
  3914.   are made to step into calls to protected-mode subroutines.  These subroutines
  3915.   must be debugged using other methods.  This appendix presents useful
  3916.   information that should aid the programmer toward this end.
  3917.        Debugging protected-mode code without the aid of a software debugger will
  3918.   not prove as limiting as it may sound.  In some cases there are better
  3919.   alternatives to software debuggers.  For example, many programmers waste time
  3920.   stepping through code with a debugger trying to resolve a processor exception
  3921.   condition when a quick resolution to the problem could be gained with a deeper
  3922.   understanding of the processor and the exception.
  3923.  
  3924.  
  3925.   Resolving Bugs Affecting Program Output
  3926.  
  3927.  
  3928.        Bugs which lead to erroneous program output can typically be diagnosed
  3929.   with strategically located print statements.  The XLIB archive contains a file
  3930.   call PMIO.INC which contains many protected-mode input/output routines,
  3931.   including a variety of print routines.  The print routines never call BIOS or
  3932.   DOS (they use direct screen writes); consequently, they will work fine both in
  3933.   interrupt handlers and the main thread of execution.
  3934.        A similar method for locating bugs involves strategic location of the INT
  3935.   3 instruction.  This instruction will generate a breakpoint exception.  The
  3936.   exception handlers in XLIBE will then give a complete report on register
  3937.   status as of the INT 3.  The programmer will then be given the option to
  3938.   resume execution.
  3939.  
  3940.  
  3941.   Resolving Bugs Causing Processor Exceptions
  3942.  
  3943.  
  3944.        Bugs causing processor exceptions will commonly occur in protected mode.
  3945.   These bugs can be particularly annoying because they often hang or reboot the
  3946.   machine or leave it in an unstable state.  However, the exception handlers in
  3947.   XLIBE should be able to successfully trap such bugs and then terminate the
  3948.   program in an orderly fashion.
  3949.        If the exception handlers in XLIBE fail to trap an exception, then it is
  3950.   likely the case that the bug is corrupting data or code used by the handlers.
  3951.   In any event, other methods may be used to track the bug.
  3952.        Once protected mode has been entered by calling either CALLPM or ENTERPM,
  3953.   one may return to the real-mode caller from any point in the code with a jump
  3954.   to either RETPM or EXITPM.  Therefore, if an unidentified instruction is
  3955.   generating exceptions in protected mode, one may locate the instruction by
  3956.   placing jumps to RETPM or ENTERPM at various locations in the code.  Initially
  3957.   the jumps should be placed early in the code and then moved forward.  This way
  3958.  
  3959.  
  3960.  
  3961.                                         57
  3962.  
  3963.  
  3964.  
  3965.  
  3966.  
  3967.  
  3968.   the processor exception is avoided as it is searched, thereby saving the time
  3969.   necessary to reboot after the exception occurs.
  3970.        XLIB is also designed such that INT 21H, function 4CH should terminate a
  3971.   program from either real or protected mode.  This provides an alternative way
  3972.   to exit the program before execution of a faulty instruction.
  3973.        Processor exceptions are not generally difficult to resolve if the
  3974.   programmer has a thorough understanding of the exception.  When an exception
  3975.   occurs, the exception handlers in XLIBE will print a report of register state
  3976.   to the screen.  The exception usually can be resolved by examining this
  3977.   report.  In particular, the report will contain the CS:EIP at which the
  3978.   exception occurred.  Using this information, the programmer can typically
  3979.   identify the problematic instruction by examining a list file generated by the
  3980.   assembler or compiler.
  3981.  
  3982.  
  3983.   Processor Exceptions and Their Causes
  3984.  
  3985.  
  3986.        Many processor exceptions issue error codes.  The exception handlers in
  3987.   XLIBE will always display such codes.  For all exceptions except page faults
  3988.   (exception #14), the error code will be nonzero if the processor can associate
  3989.   the exception with a particular segment, in which event, the error code
  3990.   identifies the segment.  In particular, bits 3-15 of the error code will be
  3991.   the selector for the segment.  Bit 1 will be set if this selector refers to a
  3992.   gate descriptor in the interrupt descriptor table.  If this bit is clear, then
  3993.   bit 2 identifies the selector as belonging to the global descriptor table (the
  3994.   bit is clear) or the local descriptor table (the bit is set).  Bit 0 is set if
  3995.   an event external to the program generated the exception.  Error codes are
  3996.   generated for exceptions:  8,10,11,12,13,14,15, and 17.
  3997.        The following is a summary of nearly all CPU exceptions:
  3998.  
  3999.   Exception #0, Divide Error - This exception occurs when a DIV or IDIV has been
  4000.   executed with a zero divisor, or when a quotient is too large to be contained
  4001.   in the targeted register (AL, AX, or EAX).
  4002.  
  4003.   Exception #1, Debug Exception - This exception occurs when a data breakpoint
  4004.   has been addressed, or upon execution of any instruction when single-step
  4005.   trapping has been enabled by setting the trap flag in the EFLAGS register.  If
  4006.   the exception is due to a data breakpoint, then the debug status register
  4007.   (DR6) identifies the breakpoint.  The lowest four bits of this register
  4008.   correspond to the four CPU breakpoint registers (DR0-DR3).  Set bits indicate
  4009.   that the corresponding breakpoint condition is satisfied.  Bit 14 of DR6 will
  4010.   be set if the exception is due to a single-step trap.  XLIB does not implement
  4011.   single-step trapping.
  4012.  
  4013.   Exception #3, Breakpoint - This exception is generated by INT 3.
  4014.  
  4015.   Exception #4, Overflow - This exception occurs when the INTO instruction is
  4016.   executed with the overflow flag being set.
  4017.  
  4018.   Exception #5, Bounds Check - This exception occurs when a BOUND instruction is
  4019.   executed with the operand violating the specified limits.
  4020.  
  4021.  
  4022.  
  4023.  
  4024.  
  4025.                                         58
  4026.  
  4027.  
  4028.  
  4029.  
  4030.  
  4031.  
  4032.   Exception #6, Invalid Opcode - This exception occurs when an unrecognizable
  4033.   instruction is encountered in the code sequence.  Provided that there are no
  4034.   bugs in the compiler, this exception is almost certainly indicative of a bad
  4035.   transfer (JMP, CALL, RET, or IRET) or of code corruption.  However, the
  4036.   exception can also be generated by instructions which are not intended for the
  4037.   current CPU mode (e.g. LLDT in real mode).
  4038.  
  4039.   Exception #7, Device Not Available - This exception occurs when an ESC
  4040.   instruction is executed under FPU emulation, or when a WAIT or ESC instruction
  4041.   is executed with the task-switch flag set in CR0.  Neither case is likely
  4042.   under XLIB.
  4043.  
  4044.   Exception #8, Double Fault - If an exception occurs while the processor is
  4045.   attempting to call an exception handler for a prior exception, and if the two
  4046.   exceptions cannot be serialized, then a double fault exception is generated.
  4047.   The error code for this exception is always zero.  Under XLIB, double faults
  4048.   are generally indicative of corruption of XLIB data used by the exception
  4049.   handlers.
  4050.  
  4051.   Exception #10, Invalid Task-State Segment - This exception occurs when an
  4052.   attempt is made to perform a task switch to a task having an invalid task-
  4053.   state segment.  Since XLIB performs task switches only when servicing
  4054.   exceptions themselves, this condition generally derives from code corruption
  4055.   or an invalid transfer.
  4056.  
  4057.   Exception #11, Segment Not Present - This exception occurs when an attempt is
  4058.   made to load a segment register with a descriptor which is marked not-present.
  4059.   A segment might be so marked if its contents have been swapped to disk.  Since
  4060.   all of the descriptors in XLIB are marked present, this exception likely
  4061.   derives from either corruption of the descriptor tables or an attempt to load
  4062.   a selector for an uninitialized descriptor.
  4063.  
  4064.   Exception #12, Stack Exception - Most stack exceptions are caused by limit
  4065.   violations in ESP or EBP.  For example, if the value in ESP is beyond the
  4066.   stack segment limit then a PUSH or POP will generate a stack exception.  It is
  4067.   also possible to have an "expand-down" stack where the segment limit is
  4068.   interpreted as a lower bound.  In such cases a stack exception could be
  4069.   generated if a value in ESP or EBP were too small.  Stack exceptions can also
  4070.   occur when SS is loaded with a selector for a descriptor which is marked not-
  4071.   present.
  4072.        Stack exceptions are generally common; however, they should be uncommon
  4073.   for XLIB programs while in protected mode.  This follows because XLIB uses an
  4074.   expand-up stack with a FFFFFFFFH limit.  Unless a switch has been made from
  4075.   the default stack, a stack exception under XLIB would typically be indicative
  4076.   of an invalid value being loaded to SS.
  4077.  
  4078.   Exception #13, General Protection Violation - This notorious exception is a
  4079.   catchall category on Intel processors that may be generated by a number of
  4080.   conditions.  However, three conditions account for nearly all such exceptions
  4081.   in practice.  These are:  1) An invalid value was loaded to a segment
  4082.   register, 2) An attempt was made to write to a code segment, or 3) Privilege
  4083.   rules were violated.
  4084.        Novices to protected mode often forget that segment registers must
  4085.   contain selectors in this mode.  Invalid values are also frequently popped
  4086.  
  4087.  
  4088.  
  4089.                                         59
  4090.  
  4091.  
  4092.  
  4093.  
  4094.  
  4095.  
  4096.   from the stack into segment registers because the stack has been corrupted or
  4097.   because the stack pointer has not been properly maintained.
  4098.        It must be remembered that writes to code segments are illegal in
  4099.   protected mode.  That is, one cannot write to a code segment through the CS
  4100.   register.  If code modification is desired, then load a data segment register
  4101.   with a selector to a descriptor which maps the code segment.  The CSEGDSEL and
  4102.   TSEGDSEL selectors are included in XLIB for this purpose.
  4103.        Protected-mode programs can run at four different privilege levels.  The
  4104.   highest is level zero and the lowest is level three.  XLIB programs will
  4105.   either be operating at the highest or lowest level.  Real-mode code always
  4106.   operates at level zero.  If a memory manager other than HIMEM.SYS is
  4107.   installed, then the machine is likely using virtual 8086 mode in lieu of real
  4108.   mode.  This is also the case under Windows and OS/2.  Virtual 8086 mode is a
  4109.   subset of protected mode wherein real mode is simulated.  Virtual 8086 mode
  4110.   always operates at level three.
  4111.        XLIB programs operating under DPMI will nearly always be at level three.
  4112.   Under VCPI the privilege level will depend upon the CPU mode. In protected
  4113.   mode the privilege level is zero, but in virtual 8086 mode the privilege level
  4114.   is three.  If neither DPMI nor VCPI are present, then XLIB programs will
  4115.   operate at level zero regardless of CPU mode.
  4116.        A program operating at level three is always under the supervision of
  4117.   another program at level zero.  The supervisor program will typically be a
  4118.   memory manager, Windows, or OS/2.  When the level three program attempts to
  4119.   execute a privileged instruction, the supervisor program is informed of the
  4120.   attempt by the processor.  The supervisor program may then execute the
  4121.   instruction in behalf of the unprivileged program, or it may terminate the
  4122.   unprivileged program with a privileged operation violation.
  4123.        Privileged instructions include reads and writes to IO ports and
  4124.   alterations to the interrupt flag.  Both of these types of instructions are
  4125.   generally permitted by the supervisor program.  However, other instructions (
  4126.   e.g. LGDT) will be denied.
  4127.        XLIB programmers have little occasion to use inadmissible privileged
  4128.   instructions.  Therefore privileged operation exceptions are nearly always
  4129.   indicative of code corruption or of an invalid transfer.
  4130.  
  4131.   Exception #14, Page Fault - A principal protection mechanism of the processor
  4132.   is its memory paging mode.  In this mode, memory is divided into 4K pages with
  4133.   the divisions being at 4K boundaries.  A memory manager can mark certain pages
  4134.   as being absent, read-only, or privileged.  An attempt to access an absent
  4135.   page or to write a read-only page always generates a page fault.  A privileged
  4136.   page can be accessed only by code operating at privilege levels higher than
  4137.   three; hence, a page fault will occur if code at level three attempts to
  4138.   access such pages.
  4139.        When a page fault occurs, an error code is supplied by the processor to
  4140.   describe the fault.  The error code is defined only in the lowest three bits.
  4141.   The zero bit describes whether the exception was caused by access of a not-
  4142.   present page (the bit is clear) or by a protection violation (the bit is set).
  4143.   Protection violations occur with attempts to access privileged pages or
  4144.   attempts to write read-only pages.  Bit two of the error code describes the
  4145.   privilege mode at which the exception occurred.  If the bit is clear, then the
  4146.   processor was executing in privileged mode.  In this case, protection
  4147.   violations are generated only by attempts to write read-only pages.  Bit one
  4148.   describes whether the fault took place during a read (the bit is clear) or a
  4149.   write (the bit is set).
  4150.  
  4151.  
  4152.  
  4153.                                         60
  4154.  
  4155.  
  4156.  
  4157.  
  4158.  
  4159.  
  4160.        A page fault nearly always occurs because of an attempt to access a bad
  4161.   address or an attempt to transfer control to a bad address.  Memory managers
  4162.   may mark unallocated pages as being not-present so that page faults will be
  4163.   generated whenever an attempt is made to access them.  This way the programmer
  4164.   will be alerted to bad address computations.  When VCPI is being used, XLIB
  4165.   becomes largely responsible for management of memory pages.  XLIB will in fact
  4166.   mark all unallocated pages as not present.  XLIB will mark all allocated pages
  4167.   as unprivileged and writable.
  4168.        The CR2 register will contain the address for the attempted access which
  4169.   generated the page fault.  CR2 is displayed by the exception handlers in
  4170.   XLIBE.
  4171.  
  4172.        Exception #13 and Exception #14 are by far the most common exceptions
  4173.   occurring under XLIB programming.  The following list of questions should be
  4174.   considered when attempting to resolve such exceptions.  These questions are
  4175.   also relevant to other exceptions:
  4176.  
  4177.   1)  Did you improperly maintain the stack pointer?
  4178.   2)  Did you forget that only selectors can be loaded to segment registers in
  4179.       protected mode?
  4180.   3)  Did you compute an address incorrectly?
  4181.   4)  Did you attempt to write to a code segment using CS override?
  4182.   5)  Did you fail to terminate a subroutine with RET?
  4183.   6)  Did you forget to properly match CALL (far or near) and RET (e.g. Did you
  4184.       forget that TSEG procedures must be near)?
  4185.   7)  Did you attempt to execute a privileged instruction?
  4186.   8)  Did you fail to terminate an interrupt handler with IRET?
  4187.   9)  Did you terminate a protected-mode interrupt handler with IRET instead of
  4188.       IRETD?
  4189.   10) If you are a TASM programmer, did you fail to specify LARGESTACK in your
  4190.       TSEG code?
  4191.  
  4192.  
  4193.   Miscellaneous Debugging Tips
  4194.  
  4195.  
  4196.        If a program runs unpredictably even when executed under identical
  4197.   circumstances, then the problem is due to an asynchronous phenomenon.  This
  4198.   almost definitely implies a problem with a hardware interrupt handler.  Such
  4199.   problems are oftentimes associated with the timer tick interrupt.  This theory
  4200.   can sometimes be tested by disabling certain hardware interrupts with the
  4201.   interrupt mask register.  The interrupt mask register for IRQs 0 through 7 is
  4202.   at port 21H.  The masks for IRQs 8 through 15 are at port A1H.  Set bits
  4203.   disable the corresponding IRQ.  For example, the following code sequence would
  4204.   disable the timer tick interrupt (IRQ 0):
  4205.  
  4206.   IN    AL,21H
  4207.   OR    AL,01H
  4208.   OUT   21H,AL
  4209.  
  4210.        If a program leaves the machine in an unstable state, then it is possible
  4211.   that XLIB is not being terminated correctly.  Try running an unregistered copy
  4212.   of XLIB and see if the registration reminder message is printed to the screen
  4213.  
  4214.  
  4215.  
  4216.  
  4217.                                         61
  4218.  
  4219.  
  4220.  
  4221.  
  4222.  
  4223.  
  4224.   at program termination.  If not, then the XLIB termination handler is likely
  4225.   not receiving control.  This is likely due to code corruption.
  4226.        Most subroutines intended for protected-mode will also operate in real
  4227.   mode when applied to small problems.  If a software debugger is deemed
  4228.   necessary, one might develop code in real mode and then convert to protected
  4229.   mode after debugging.  32-bit registers are admissible in real mode provided
  4230.   that no such register is used as a base or index register while containing a
  4231.   value greater than FFFFH.
  4232.  
  4233.  
  4234.  
  4235.  
  4236.  
  4237.  
  4238.  
  4239.  
  4240.  
  4241.  
  4242.  
  4243.  
  4244.  
  4245.  
  4246.  
  4247.  
  4248.  
  4249.  
  4250.  
  4251.  
  4252.  
  4253.  
  4254.  
  4255.  
  4256.  
  4257.  
  4258.  
  4259.  
  4260.  
  4261.  
  4262.  
  4263.  
  4264.  
  4265.  
  4266.  
  4267.  
  4268.  
  4269.  
  4270.  
  4271.  
  4272.  
  4273.  
  4274.  
  4275.  
  4276.  
  4277.  
  4278.  
  4279.  
  4280.  
  4281.                                         62